From 02248f3fbff9d8c991ebd0ec146e26c863fc9e2c Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <41978171+jin1xiao3long2@users.noreply.github.com> Date: Sat, 24 Apr 2021 01:16:26 +0800 Subject: [PATCH 01/16] Create CMakeLists.txt can use rapidjson and muduo --- CMakeLists.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3eb1f68 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.0) + +project(pro) + +SET(CMAKE_CXX_FLAGS -pthread) +find_package(RapidJSON REQUIRED) + +include_directories(${RapidJSON_INCLUDE_DIR}) +include_directories(include) + +link_directories("lib") + +add_executable(testC test.cpp) + + +target_link_libraries(testC ${RapidJSON_LIBS}) +target_link_libraries(testC libmuduo_net.a libmuduo_base.a) From 78b8ff5e971c9b01e90976be418b97adeae99a39 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 Date: Sun, 25 Apr 2021 21:07:21 +0800 Subject: [PATCH 02/16] update README.md --- .gitignore | 3 ++ README.md | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f0d827 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +lib/ +include/ diff --git a/README.md b/README.md index f468905..28f0b76 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,88 @@ # cids-servers center server ,mirror server and driver + + +dir +----cids-server +----rapidjson +----nanodbc +----muduo + +after clone this project + +Imporve projectPath + +-- mkdir lib #to find libraries +-- mkdir include #to find headers + +Compile rapidJson + +git clone https://github.com/Tencent/rapidjson.git #download rapidjson + +cd rapidjson #change to rapidjson dir + +mkdir build #Put compiler output in build file + +cd build #change to build dir + +cmake .. #generate Makefile + +make #generate other things you can add '-j4' after 'make' to make it faster + +sudo make install #generate lib files and put them in /usr/lib(maybe) + + +Compile nanodbc + +git clone https://github.com/nanodbc/nanodbc.git #download nanodbc + +cd nanodbc #change to nanodbc dir + +cp -r nanodbc ../cids-servser/include #copy include file to projectPath/include + +mkdir build #Put compiler output in build file + +cd build #change to build dir + +cmake .. #generate Makefile + +make #generate other things you can add '-j4' after 'make' to make it faster + +cp libnanodbc.a ../../cids-servers/lib #copy library file to projectPath/lib + + +Compiler muduo + +git clone https://github.com/chenshuo/muduo.git #download muduo + +cd muduo #change to muduo dir + +cp -r muduo ../cids-servser/include #copy include file to projectPath/include + +mkdir build #Put compiler output in build file + +cd build #change to build dir + +cmake .. #generate Makefile + +make #generate other things you can add '-j4' after 'make' to make it faster + +cd lib #change to lib dir + +cp * ../../../cids-servsers/lib #put lib file to projectPath/lib + + +now your project will like this: + +cids-servsers +----include + ----muduo + ----net + ----base + ----nanodbc +----lib + ----libxxx.a #10 lib files + + + + From 8c7a0e2b7aaa76a87c4d414356b9f327a72d2f37 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <157027148@qq.com> Date: Sun, 25 Apr 2021 21:32:59 +0800 Subject: [PATCH 03/16] update CMakeLists.txt --- .ssh | 38 ++++++++++++++++++++++++++++++++++++++ .ssh.pub | 1 + 2 files changed, 39 insertions(+) create mode 100644 .ssh create mode 100644 .ssh.pub diff --git a/.ssh b/.ssh new file mode 100644 index 0000000..b0de99a --- /dev/null +++ b/.ssh @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn +NhAAAAAwEAAQAAAYEA1i1beTdjDztxcO1/W5cMNfkhjFlZW041racTTNE5p933NOeXL6yh +lDhEJS3x1jqrh96EzGKAIHATSS4vCjG7ZP6xXFDBVl8Ov/QajX92xibwx8znjaUuY3JyMF +EckIk7GlS6fGy947ry5ipnSTUETN+2EXBD9WQEHeyNoe7HGNy8q6Fl7E6wiRc+sLcDtc3u +jPDwPuRp+xc94feUKmGfX2IEeZBjZWGGPeZmIHXM9HduLrFdb3V20mOIRvDA4FVuoOulHt +I0lHJUKQK26nX1lm0SVEs7FlT0NHIntj2vja6LWOACfNtBWhaFkRV0k8UCTbUIbVY1Yn+K +59OElAEHpCTsoyen0sm6pq/31UNNOGJmEFVXKa0oqAmZ7RYkw2JKSy0+sfw5Ztv7j9WUEY +fQlBnGvCjqnxNftmON8BxYBvJ2X9J52Gamfc7v4DGJTkwi1lL12fqZd5Hmx2Hdxwupuxgm +y7kgXlk9lfMnR5xKjx7E0rZ9Egkevg9fPLAYUJzdAAAFiIdib7mHYm+5AAAAB3NzaC1yc2 +EAAAGBANYtW3k3Yw87cXDtf1uXDDX5IYxZWVtONa2nE0zROafd9zTnly+soZQ4RCUt8dY6 +q4fehMxigCBwE0kuLwoxu2T+sVxQwVZfDr/0Go1/dsYm8MfM542lLmNycjBRHJCJOxpUun +xsveO68uYqZ0k1BEzfthFwQ/VkBB3sjaHuxxjcvKuhZexOsIkXPrC3A7XN7ozw8D7kafsX +PeH3lCphn19iBHmQY2Vhhj3mZiB1zPR3bi6xXW91dtJjiEbwwOBVbqDrpR7SNJRyVCkCtu +p19ZZtElRLOxZU9DRyJ7Y9r42ui1jgAnzbQVoWhZEVdJPFAk21CG1WNWJ/iufThJQBB6Qk +7KMnp9LJuqav99VDTThiZhBVVymtKKgJme0WJMNiSkstPrH8OWbb+4/VlBGH0JQZxrwo6p +8TX7ZjjfAcWAbydl/Sedhmpn3O7+AxiU5MItZS9dn6mXeR5sdh3ccLqbsYJsu5IF5ZPZXz +J0ecSo8exNK2fRIJHr4PXzywGFCc3QAAAAMBAAEAAAGAPopWGKpMucjw0jn3o4YS4bvSyQ +naJuhKkl+kKh06ScNuCTvLEPfG4uIfPAATiyvspKscehYVNeOkLg1XXRGyl8YrgjpuiksN +oo2kJ0deJnR+gMlboCfoyM9Feshkn+wCnyi4n9adCF+xx/X/3QenLs9wed0fawt+jEJkBT +IVXzQtv6xMd9lugUmRW8bFRZRRoURF0wedzt01i8Ngt5N0F0Um61x3OcZljbO2hKoBZC1v +tiDCmOZjAQJha92nZJptP7t+89/67mpgZe0dIOOFzm223H5kkT5hiw5Je+Ia8kUFaV48Yg +kWBm9vcAkyRyWuuEigVqf5Yp/JW+dcCnXXj1U4vmpy5e5FY29HOaJVEIgJmSNxDznISw28 +/l/Sxr2LZ1vXAYSXe+kwdB499tL4AKjVjWXj7Vd2jl9tH28qYQ4ne2ukOsUpzsSzvjjkBk +XVmeDJuxFxMflWzyxoHn/8/QMFTby881RuzoLObo8syjXXIZNsBNUx5PzrNQVfhGGhAAAA +wQCz5z3V01aOW0SBTt/aCcR47HA5wITtSE+cSXYiJAardvlOeA1BGbl3lfPjI84BrnT5TB +TVV+itwZRb8LEndp/NN8c5Pc/jVWgo/BjJLnz86IanIRUt6NWSKmdE/zwv7p/Jp32sYcar +tulTShDmmonnMBimGKBpj8h3cjEiZ6GNsLHkFZXhTK/9GVTxT3n80w5L8hmO13OxVXhCzg +96+GSWlv07Uo4v+xcJwiPq0mlMcs+df75wiCGwq8WanusS9pMAAADBAOzvU3WjhptOM5vK +MdnIiEwyBDZUSnwcUCYHS4YreyAoCj+lcNP6RGEdDmHnHU0IHnJNAYG9F1ad4fXjYjU0sE +dvKEs6+y3mMF1KQhKmxdh6VAfLImA3QguqtrzRNgpsQeM+yFvoLaaV7yuMcQl8C1th+U9K +7L9tZM0CQSoIj+/ZD/Fmmxr2qvJqSIRc5p2ysPijms6dJtozB1FfUyBwpACjsptsMM609m +mr2H3vWQRjkKXnP3zMg2yDxd18DdL3NQAAAMEA52k9lw6d8SaavDVIIcBfhoPPXJfoPxwR +533xM3zgiMMKXtXQpkAqlPk5+iiZD5jyfgB+Cm2uUz8nUunOvQCQ0KPXKByZzctL31xImm +s2BCMrVzlkR9LuuDi8JvzoUhX9NeW8RIGJ2fnEPoaeEwQlz2NLsJcTHRJFKE6J1EscwHKh +5hem2CxaXPsS5jWk0/h93oJYtI7RzS/hsChom2TdZWAoCQ0alNOyzpAYEe5kxKjb636YPK +04SNNrOKRxT7wJAAAAEDE1NzAyNzE0OEBxcS5jb20BAg== +-----END OPENSSH PRIVATE KEY----- diff --git a/.ssh.pub b/.ssh.pub new file mode 100644 index 0000000..2f46165 --- /dev/null +++ b/.ssh.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWLVt5N2MPO3Fw7X9blww1+SGMWVlbTjWtpxNM0Tmn3fc055cvrKGUOEQlLfHWOquH3oTMYoAgcBNJLi8KMbtk/rFcUMFWXw6/9BqNf3bGJvDHzOeNpS5jcnIwURyQiTsaVLp8bL3juvLmKmdJNQRM37YRcEP1ZAQd7I2h7scY3LyroWXsTrCJFz6wtwO1ze6M8PA+5Gn7Fz3h95QqYZ9fYgR5kGNlYYY95mYgdcz0d24usV1vdXbSY4hG8MDgVW6g66Ue0jSUclQpArbqdfWWbRJUSzsWVPQ0cie2Pa+NrotY4AJ820FaFoWRFXSTxQJNtQhtVjVif4rn04SUAQekJOyjJ6fSybqmr/fVQ004YmYQVVcprSioCZntFiTDYkpLLT6x/Dlm2/uP1ZQRh9CUGca8KOqfE1+2Y43wHFgG8nZf0nnYZqZ9zu/gMYlOTCLWUvXZ+pl3kebHYd3HC6m7GCbLuSBeWT2V8ydHnEqPHsTStn0SCR6+D188sBhQnN0= 157027148@qq.com From 3701cd506f355ed0569dbec97f5d7002f0fe787e Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <157027148@qq.com> Date: Sun, 25 Apr 2021 21:42:33 +0800 Subject: [PATCH 04/16] update README.md --- README.md | 122 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 28f0b76..1fa485b 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,122 @@ # cids-servers + center server ,mirror server and driver -dir -----cids-server -----rapidjson -----nanodbc -----muduo + +your project path and other library project path should be like this: + + + +- dir + + - cids-server + + - rapidjson + - nanodbc + + - muduo + + after clone this project -Imporve projectPath --- mkdir lib #to find libraries --- mkdir include #to find headers -Compile rapidJson +## Imporve projectPath + +```bash +-- mkdir lib #to find libraries + +-- mkdir include #to find headers +``` + +------ + + + +## Compile rapidJson + +```bash +git clone #download rapidjson + +cd rapidjson #change to rapidjson dir + +mkdir build #Put compiler output in build file + +cd build #change to build dir + +cmake .. #generate Makefile -git clone https://github.com/Tencent/rapidjson.git #download rapidjson +make #generate other things you can add '-j4' after 'make' to make it faster -cd rapidjson #change to rapidjson dir +sudo make install #generate lib files and put them in /usr/lib(maybe) +``` -mkdir build #Put compiler output in build file +------ -cd build #change to build dir -cmake .. #generate Makefile -make #generate other things you can add '-j4' after 'make' to make it faster +## Compile nanodbc -sudo make install #generate lib files and put them in /usr/lib(maybe) +```bash +git clone #download nanodbc +cd nanodbc #change to nanodbc dir -Compile nanodbc +cp -r nanodbc ../cids-servser/include #copy include file to projectPath/include -git clone https://github.com/nanodbc/nanodbc.git #download nanodbc +mkdir build #Put compiler output in build file -cd nanodbc #change to nanodbc dir +cd build #change to build dir -cp -r nanodbc ../cids-servser/include #copy include file to projectPath/include +cmake .. #generate Makefile -mkdir build #Put compiler output in build file +make #generate other things you can add '-j4' after 'make' to make it faster -cd build #change to build dir +cp libnanodbc.a ../../cids-servers/lib #copy library file to projectPath/lib +``` -cmake .. #generate Makefile +------ -make #generate other things you can add '-j4' after 'make' to make it faster -cp libnanodbc.a ../../cids-servers/lib #copy library file to projectPath/lib +## Compiler muduo -Compiler muduo +```bash +git clone #download muduo -git clone https://github.com/chenshuo/muduo.git #download muduo +cd muduo #change to muduo dir -cd muduo #change to muduo dir +cp -r muduo ../cids-servser/include #copy include file to projectPath/include -cp -r muduo ../cids-servser/include #copy include file to projectPath/include +mkdir build #Put compiler output in build file -mkdir build #Put compiler output in build file +cd build #change to build dir -cd build #change to build dir +cmake .. #generate Makefile -cmake .. #generate Makefile +make #generate other things you can add '-j4' after 'make' to make it faster -make #generate other things you can add '-j4' after 'make' to make it faster +cd lib #change to lib dir -cd lib #change to lib dir +cp * ../../../cids-servsers/lib #put lib file to projectPath/lib -cp * ../../../cids-servsers/lib #put lib file to projectPath/lib +``` +------ -now your project will like this: -cids-servsers -----include - ----muduo - ----net - ----base - ----nanodbc -----lib - ----libxxx.a #10 lib files +## now your project will like this: +- cids-servsers + - include + - muduo + - net + - base + - nanodbc + - lib + - libxxx.a #10 lib files From 78e8961dcbbd9c0d67492af2a1cc864561df77d4 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <157027148@qq.com> Date: Sun, 25 Apr 2021 21:58:37 +0800 Subject: [PATCH 05/16] update CMakeLists.txt --- .ssh | 38 -------------------------------------- .ssh.pub | 1 - CMakeLists.txt | 1 + README.md | 21 ++++++++++++++++++++- 4 files changed, 21 insertions(+), 40 deletions(-) delete mode 100644 .ssh delete mode 100644 .ssh.pub diff --git a/.ssh b/.ssh deleted file mode 100644 index b0de99a..0000000 --- a/.ssh +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn -NhAAAAAwEAAQAAAYEA1i1beTdjDztxcO1/W5cMNfkhjFlZW041racTTNE5p933NOeXL6yh -lDhEJS3x1jqrh96EzGKAIHATSS4vCjG7ZP6xXFDBVl8Ov/QajX92xibwx8znjaUuY3JyMF -EckIk7GlS6fGy947ry5ipnSTUETN+2EXBD9WQEHeyNoe7HGNy8q6Fl7E6wiRc+sLcDtc3u -jPDwPuRp+xc94feUKmGfX2IEeZBjZWGGPeZmIHXM9HduLrFdb3V20mOIRvDA4FVuoOulHt -I0lHJUKQK26nX1lm0SVEs7FlT0NHIntj2vja6LWOACfNtBWhaFkRV0k8UCTbUIbVY1Yn+K -59OElAEHpCTsoyen0sm6pq/31UNNOGJmEFVXKa0oqAmZ7RYkw2JKSy0+sfw5Ztv7j9WUEY -fQlBnGvCjqnxNftmON8BxYBvJ2X9J52Gamfc7v4DGJTkwi1lL12fqZd5Hmx2Hdxwupuxgm -y7kgXlk9lfMnR5xKjx7E0rZ9Egkevg9fPLAYUJzdAAAFiIdib7mHYm+5AAAAB3NzaC1yc2 -EAAAGBANYtW3k3Yw87cXDtf1uXDDX5IYxZWVtONa2nE0zROafd9zTnly+soZQ4RCUt8dY6 -q4fehMxigCBwE0kuLwoxu2T+sVxQwVZfDr/0Go1/dsYm8MfM542lLmNycjBRHJCJOxpUun -xsveO68uYqZ0k1BEzfthFwQ/VkBB3sjaHuxxjcvKuhZexOsIkXPrC3A7XN7ozw8D7kafsX -PeH3lCphn19iBHmQY2Vhhj3mZiB1zPR3bi6xXW91dtJjiEbwwOBVbqDrpR7SNJRyVCkCtu -p19ZZtElRLOxZU9DRyJ7Y9r42ui1jgAnzbQVoWhZEVdJPFAk21CG1WNWJ/iufThJQBB6Qk -7KMnp9LJuqav99VDTThiZhBVVymtKKgJme0WJMNiSkstPrH8OWbb+4/VlBGH0JQZxrwo6p -8TX7ZjjfAcWAbydl/Sedhmpn3O7+AxiU5MItZS9dn6mXeR5sdh3ccLqbsYJsu5IF5ZPZXz -J0ecSo8exNK2fRIJHr4PXzywGFCc3QAAAAMBAAEAAAGAPopWGKpMucjw0jn3o4YS4bvSyQ -naJuhKkl+kKh06ScNuCTvLEPfG4uIfPAATiyvspKscehYVNeOkLg1XXRGyl8YrgjpuiksN -oo2kJ0deJnR+gMlboCfoyM9Feshkn+wCnyi4n9adCF+xx/X/3QenLs9wed0fawt+jEJkBT -IVXzQtv6xMd9lugUmRW8bFRZRRoURF0wedzt01i8Ngt5N0F0Um61x3OcZljbO2hKoBZC1v -tiDCmOZjAQJha92nZJptP7t+89/67mpgZe0dIOOFzm223H5kkT5hiw5Je+Ia8kUFaV48Yg -kWBm9vcAkyRyWuuEigVqf5Yp/JW+dcCnXXj1U4vmpy5e5FY29HOaJVEIgJmSNxDznISw28 -/l/Sxr2LZ1vXAYSXe+kwdB499tL4AKjVjWXj7Vd2jl9tH28qYQ4ne2ukOsUpzsSzvjjkBk -XVmeDJuxFxMflWzyxoHn/8/QMFTby881RuzoLObo8syjXXIZNsBNUx5PzrNQVfhGGhAAAA -wQCz5z3V01aOW0SBTt/aCcR47HA5wITtSE+cSXYiJAardvlOeA1BGbl3lfPjI84BrnT5TB -TVV+itwZRb8LEndp/NN8c5Pc/jVWgo/BjJLnz86IanIRUt6NWSKmdE/zwv7p/Jp32sYcar -tulTShDmmonnMBimGKBpj8h3cjEiZ6GNsLHkFZXhTK/9GVTxT3n80w5L8hmO13OxVXhCzg -96+GSWlv07Uo4v+xcJwiPq0mlMcs+df75wiCGwq8WanusS9pMAAADBAOzvU3WjhptOM5vK -MdnIiEwyBDZUSnwcUCYHS4YreyAoCj+lcNP6RGEdDmHnHU0IHnJNAYG9F1ad4fXjYjU0sE -dvKEs6+y3mMF1KQhKmxdh6VAfLImA3QguqtrzRNgpsQeM+yFvoLaaV7yuMcQl8C1th+U9K -7L9tZM0CQSoIj+/ZD/Fmmxr2qvJqSIRc5p2ysPijms6dJtozB1FfUyBwpACjsptsMM609m -mr2H3vWQRjkKXnP3zMg2yDxd18DdL3NQAAAMEA52k9lw6d8SaavDVIIcBfhoPPXJfoPxwR -533xM3zgiMMKXtXQpkAqlPk5+iiZD5jyfgB+Cm2uUz8nUunOvQCQ0KPXKByZzctL31xImm -s2BCMrVzlkR9LuuDi8JvzoUhX9NeW8RIGJ2fnEPoaeEwQlz2NLsJcTHRJFKE6J1EscwHKh -5hem2CxaXPsS5jWk0/h93oJYtI7RzS/hsChom2TdZWAoCQ0alNOyzpAYEe5kxKjb636YPK -04SNNrOKRxT7wJAAAAEDE1NzAyNzE0OEBxcS5jb20BAg== ------END OPENSSH PRIVATE KEY----- diff --git a/.ssh.pub b/.ssh.pub deleted file mode 100644 index 2f46165..0000000 --- a/.ssh.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWLVt5N2MPO3Fw7X9blww1+SGMWVlbTjWtpxNM0Tmn3fc055cvrKGUOEQlLfHWOquH3oTMYoAgcBNJLi8KMbtk/rFcUMFWXw6/9BqNf3bGJvDHzOeNpS5jcnIwURyQiTsaVLp8bL3juvLmKmdJNQRM37YRcEP1ZAQd7I2h7scY3LyroWXsTrCJFz6wtwO1ze6M8PA+5Gn7Fz3h95QqYZ9fYgR5kGNlYYY95mYgdcz0d24usV1vdXbSY4hG8MDgVW6g66Ue0jSUclQpArbqdfWWbRJUSzsWVPQ0cie2Pa+NrotY4AJ820FaFoWRFXSTxQJNtQhtVjVif4rn04SUAQekJOyjJ6fSybqmr/fVQ004YmYQVVcprSioCZntFiTDYkpLLT6x/Dlm2/uP1ZQRh9CUGca8KOqfE1+2Y43wHFgG8nZf0nnYZqZ9zu/gMYlOTCLWUvXZ+pl3kebHYd3HC6m7GCbLuSBeWT2V8ydHnEqPHsTStn0SCR6+D188sBhQnN0= 157027148@qq.com diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eb1f68..4f298f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,3 +15,4 @@ add_executable(testC test.cpp) target_link_libraries(testC ${RapidJSON_LIBS}) target_link_libraries(testC libmuduo_net.a libmuduo_base.a) +target_link_libraries(testC libnanodbc.a) diff --git a/README.md b/README.md index 1fa485b..0081d8d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,25 @@ sudo make install #generate lib files and put them in /usr/lib(maybe) ## Compile nanodbc +Before you compile nanodbc, you should download UnixOdbc: + +download unixODBC-2.3.0.tar.gz + +```bash +tar -xzvf unixODBC-2.3.0.tar.gz + +cd unixODBC-2.3.0.tar.gz + +./configure --enable-gui=no + +make + +sudo make install + +odbc_config --version #check odbc_config is installed + +``` + ```bash git clone #download nanodbc @@ -117,6 +136,6 @@ cp * ../../../cids-servsers/lib #put lib file to projectPath/lib - base - nanodbc - lib - - libxxx.a #10 lib files + - libxxx.a #7/10 lib files From 1d7e3e4392e87a73eb255646eb4db0a25388c98f Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <41978171+jin1xiao3long2@users.noreply.github.com> Date: Tue, 27 Apr 2021 21:57:55 +0800 Subject: [PATCH 06/16] Update README.md --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0081d8d..79c450a 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,9 @@ sudo make install #generate lib files and put them in /usr/lib(maybe) Before you compile nanodbc, you should download UnixOdbc: -download unixODBC-2.3.0.tar.gz +### download unixODBC-2.3.0.tar.gz + +Download unixODBC-2.3.0.tar.gz ,you can also use `sudo apt install unixodbc ` to download but it's unuseful to my system ```bash tar -xzvf unixODBC-2.3.0.tar.gz @@ -78,6 +80,23 @@ odbc_config --version #check odbc_config is installed ``` +### download odbc-mariadb +{ + `sudo apt install odbc-mariadb` + + TO BE CONTINUED!!!! +} + +### configure odbc-mariadb + +see complete info on "https://mariadb.com/kb/en/creating-a-data-source-with-mariadb-connectorodbc/" + +[MariaDB ODBC 3.0 Driver] +Description = MariaDB Connector/ODBC v.3.0 +Driver=/usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so + + + ```bash git clone #download nanodbc From a30a4a2dcf5c33dbac1bfb4cd1876735220a4a75 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <41978171+jin1xiao3long2@users.noreply.github.com> Date: Fri, 30 Apr 2021 14:57:55 +0800 Subject: [PATCH 07/16] Update README.md update odbc lib --- README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 79c450a..9b4d484 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,13 @@ sudo make install #generate lib files and put them in /usr/lib(maybe) Before you compile nanodbc, you should download UnixOdbc: -### download unixODBC-2.3.0.tar.gz +### download mariadb and configure + +### download unixodbc + +` sudo apt install unixodbc ` + +### download unixODBC-2.3.0.tar.gz -> to download odbc_config Download unixODBC-2.3.0.tar.gz ,you can also use `sudo apt install unixodbc ` to download but it's unuseful to my system @@ -84,7 +90,6 @@ odbc_config --version #check odbc_config is installed { `sudo apt install odbc-mariadb` - TO BE CONTINUED!!!! } ### configure odbc-mariadb @@ -102,8 +107,6 @@ git clone #download nanodbc cd nanodbc #change to nanodbc dir -cp -r nanodbc ../cids-servser/include #copy include file to projectPath/include - mkdir build #Put compiler output in build file cd build #change to build dir @@ -112,8 +115,21 @@ cmake .. #generate Makefile make #generate other things you can add '-j4' after 'make' to make it faster -cp libnanodbc.a ../../cids-servers/lib #copy library file to projectPath/lib +sudo make install #add lib to your env + ``` +add these statements to your CMakeLists.txt + +```cmake +if (NOT TARGET nanodbc) + find_package(nanodbc CONFIG REQUIRED) +endif() + +#add exe here + +target_link_libraries(SRC nanodbc) + + ------ From 1ec8fcf14ba160efdd1236f1018e1bb4cae4a7d3 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 Date: Sat, 15 May 2021 17:10:39 +0800 Subject: [PATCH 08/16] update from sliver branch --- .gitignore | 1 - include/Telemeter.hpp | 91 ++++ include/Type.hpp | 12 + include/Udp.hpp | 53 +++ include/boost/any.hpp | 342 ++++++++++++++ include/center/CenterConfig.txt | 48 ++ include/center/MirDescript.cpp | 0 include/center/MirDescript.h | 40 ++ include/center/TcpEcho.cpp | 40 ++ include/center/TcpEcho.h | 24 + include/center/center.cpp | 84 ++++ include/center/center.h | 46 ++ include/center/main.cpp | 22 + include/mirror/ClassInfo.h | 12 + include/mirror/Message.h | 22 + include/mirror/Mirror.h | 33 ++ include/mirror/MirrorConfig.txt | 22 + include/muduo/base/AsyncLogging.cc | 136 ++++++ include/muduo/base/AsyncLogging.h | 77 ++++ include/muduo/base/Atomic.h | 97 ++++ include/muduo/base/BUILD.bazel | 23 + include/muduo/base/BlockingQueue.h | 72 +++ include/muduo/base/BoundedBlockingQueue.h | 101 +++++ include/muduo/base/CMakeLists.txt | 34 ++ include/muduo/base/Condition.cc | 26 ++ include/muduo/base/Condition.h | 56 +++ include/muduo/base/CountDownLatch.cc | 41 ++ include/muduo/base/CountDownLatch.h | 34 ++ include/muduo/base/CurrentThread.cc | 77 ++++ include/muduo/base/CurrentThread.h | 54 +++ include/muduo/base/Date.cc | 76 ++++ include/muduo/base/Date.h | 119 +++++ include/muduo/base/Exception.cc | 18 + include/muduo/base/Exception.h | 40 ++ include/muduo/base/FileUtil.cc | 181 ++++++++ include/muduo/base/FileUtil.h | 89 ++++ include/muduo/base/GzipFile.h | 89 ++++ include/muduo/base/LogFile.cc | 133 ++++++ include/muduo/base/LogFile.h | 58 +++ include/muduo/base/LogStream.cc | 342 ++++++++++++++ include/muduo/base/LogStream.h | 203 +++++++++ include/muduo/base/Logging.cc | 227 +++++++++ include/muduo/base/Logging.h | 159 +++++++ include/muduo/base/Mutex.h | 233 ++++++++++ include/muduo/base/ProcessInfo.cc | 246 ++++++++++ include/muduo/base/ProcessInfo.h | 68 +++ include/muduo/base/Singleton.h | 77 ++++ include/muduo/base/StringPiece.h | 189 ++++++++ include/muduo/base/Thread.cc | 200 ++++++++ include/muduo/base/Thread.h | 54 +++ include/muduo/base/ThreadLocal.h | 59 +++ include/muduo/base/ThreadLocalSingleton.h | 82 ++++ include/muduo/base/ThreadPool.cc | 156 +++++++ include/muduo/base/ThreadPool.h | 67 +++ include/muduo/base/TimeZone.cc | 363 +++++++++++++++ include/muduo/base/TimeZone.h | 52 +++ include/muduo/base/Timestamp.cc | 62 +++ include/muduo/base/Timestamp.h | 123 +++++ include/muduo/base/Types.h | 123 +++++ include/muduo/base/WeakCallback.h | 65 +++ include/muduo/base/copyable.h | 19 + include/muduo/base/noncopyable.h | 20 + include/muduo/base/tests/AsyncLogging_test.cc | 64 +++ include/muduo/base/tests/Atomic_unittest.cc | 38 ++ .../muduo/base/tests/BlockingQueue_bench.cc | 106 +++++ .../muduo/base/tests/BlockingQueue_test.cc | 106 +++++ .../base/tests/BoundedBlockingQueue_test.cc | 110 +++++ include/muduo/base/tests/CMakeLists.txt | 86 ++++ include/muduo/base/tests/Date_unittest.cc | 88 ++++ include/muduo/base/tests/Exception_test.cc | 51 +++ include/muduo/base/tests/FileUtil_test.cc | 30 ++ include/muduo/base/tests/Fork_test.cc | 46 ++ include/muduo/base/tests/GzipFile_test.cc | 54 +++ include/muduo/base/tests/LogFile_test.cc | 34 ++ include/muduo/base/tests/LogStream_bench.cc | 82 ++++ include/muduo/base/tests/LogStream_test.cc | 286 ++++++++++++ include/muduo/base/tests/Logging_test.cc | 122 +++++ include/muduo/base/tests/Mutex_test.cc | 82 ++++ include/muduo/base/tests/ProcessInfo_test.cc | 17 + .../base/tests/SingletonThreadLocal_test.cc | 58 +++ include/muduo/base/tests/Singleton_test.cc | 65 +++ .../base/tests/ThreadLocalSingleton_test.cc | 58 +++ include/muduo/base/tests/ThreadLocal_test.cc | 61 +++ include/muduo/base/tests/ThreadPool_test.cc | 97 ++++ include/muduo/base/tests/Thread_bench.cc | 86 ++++ include/muduo/base/tests/Thread_test.cc | 91 ++++ include/muduo/base/tests/TimeZone_unittest.cc | 276 +++++++++++ .../muduo/base/tests/Timestamp_unittest.cc | 66 +++ include/muduo/net/Acceptor.cc | 89 ++++ include/muduo/net/Acceptor.h | 63 +++ include/muduo/net/BUILD.bazel | 51 +++ include/muduo/net/Buffer.cc | 58 +++ include/muduo/net/Buffer.h | 422 +++++++++++++++++ include/muduo/net/CMakeLists.txt | 69 +++ include/muduo/net/Callbacks.h | 82 ++++ include/muduo/net/Channel.cc | 146 ++++++ include/muduo/net/Channel.h | 113 +++++ include/muduo/net/Connector.cc | 226 +++++++++ include/muduo/net/Connector.h | 74 +++ include/muduo/net/Endian.h | 65 +++ include/muduo/net/EventLoop.cc | 278 ++++++++++++ include/muduo/net/EventLoop.h | 166 +++++++ include/muduo/net/EventLoopThread.cc | 77 ++++ include/muduo/net/EventLoopThread.h | 50 ++ include/muduo/net/EventLoopThreadPool.cc | 97 ++++ include/muduo/net/EventLoopThreadPool.h | 69 +++ include/muduo/net/InetAddress.cc | 149 ++++++ include/muduo/net/InetAddress.h | 86 ++++ include/muduo/net/Poller.cc | 29 ++ include/muduo/net/Poller.h | 71 +++ include/muduo/net/Socket.cc | 128 ++++++ include/muduo/net/Socket.h | 89 ++++ include/muduo/net/SocketsOps.cc | 316 +++++++++++++ include/muduo/net/SocketsOps.h | 64 +++ include/muduo/net/TcpClient.cc | 181 ++++++++ include/muduo/net/TcpClient.h | 90 ++++ include/muduo/net/TcpConnection.cc | 429 ++++++++++++++++++ include/muduo/net/TcpConnection.h | 161 +++++++ include/muduo/net/TcpServer.cc | 118 +++++ include/muduo/net/TcpServer.h | 120 +++++ include/muduo/net/Timer.cc | 26 ++ include/muduo/net/Timer.h | 63 +++ include/muduo/net/TimerId.h | 53 +++ include/muduo/net/TimerQueue.cc | 260 +++++++++++ include/muduo/net/TimerQueue.h | 86 ++++ include/muduo/net/ZlibStream.h | 145 ++++++ include/muduo/net/boilerplate.cc | 15 + include/muduo/net/boilerplate.h | 32 ++ include/muduo/net/http/BUILD.bazel | 9 + include/muduo/net/http/CMakeLists.txt | 30 ++ include/muduo/net/http/HttpContext.cc | 118 +++++ include/muduo/net/http/HttpContext.h | 72 +++ include/muduo/net/http/HttpRequest.h | 187 ++++++++ include/muduo/net/http/HttpResponse.cc | 47 ++ include/muduo/net/http/HttpResponse.h | 79 ++++ include/muduo/net/http/HttpServer.cc | 100 ++++ include/muduo/net/http/HttpServer.h | 68 +++ .../net/http/tests/HttpRequest_unittest.cc | 79 ++++ .../muduo/net/http/tests/HttpServer_test.cc | 150 ++++++ include/muduo/net/inspect/BUILD.bazel | 9 + include/muduo/net/inspect/CMakeLists.txt | 26 ++ include/muduo/net/inspect/Inspector.cc | 383 ++++++++++++++++ include/muduo/net/inspect/Inspector.h | 67 +++ .../muduo/net/inspect/PerformanceInspector.cc | 106 +++++ .../muduo/net/inspect/PerformanceInspector.h | 40 ++ include/muduo/net/inspect/ProcessInspector.cc | 239 ++++++++++ include/muduo/net/inspect/ProcessInspector.h | 38 ++ include/muduo/net/inspect/SystemInspector.cc | 132 ++++++ include/muduo/net/inspect/SystemInspector.h | 37 ++ include/muduo/net/inspect/tests/BUILD.bazel | 7 + .../muduo/net/inspect/tests/Inspector_test.cc | 15 + include/muduo/net/poller/DefaultPoller.cc | 27 ++ include/muduo/net/poller/EPollPoller.cc | 208 +++++++++ include/muduo/net/poller/EPollPoller.h | 55 +++ include/muduo/net/poller/PollPoller.cc | 141 ++++++ include/muduo/net/poller/PollPoller.h | 49 ++ include/muduo/net/protobuf/BufferStream.h | 56 +++ include/muduo/net/protobuf/CMakeLists.txt | 15 + .../muduo/net/protobuf/ProtobufCodecLite.cc | 243 ++++++++++ .../muduo/net/protobuf/ProtobufCodecLite.h | 192 ++++++++ include/muduo/net/protorpc/CMakeLists.txt | 42 ++ include/muduo/net/protorpc/README | 5 + include/muduo/net/protorpc/RpcChannel.cc | 184 ++++++++ include/muduo/net/protorpc/RpcChannel.h | 152 +++++++ include/muduo/net/protorpc/RpcCodec.cc | 37 ++ include/muduo/net/protorpc/RpcCodec.h | 45 ++ include/muduo/net/protorpc/RpcCodec_test.cc | 81 ++++ include/muduo/net/protorpc/RpcServer.cc | 68 +++ include/muduo/net/protorpc/RpcServer.h | 57 +++ include/muduo/net/protorpc/google-inl.h | 84 ++++ include/muduo/net/protorpc/rpc.proto | 36 ++ include/muduo/net/protorpc/rpcservice.proto | 44 ++ include/muduo/net/tests/Buffer_unittest.cc | 170 +++++++ include/muduo/net/tests/CMakeLists.txt | 48 ++ include/muduo/net/tests/Channel_test.cc | 112 +++++ .../muduo/net/tests/EchoClient_unittest.cc | 114 +++++ .../muduo/net/tests/EchoServer_unittest.cc | 86 ++++ .../net/tests/EventLoopThreadPool_unittest.cc | 68 +++ .../net/tests/EventLoopThread_unittest.cc | 48 ++ include/muduo/net/tests/EventLoop_unittest.cc | 42 ++ .../muduo/net/tests/InetAddress_unittest.cc | 70 +++ include/muduo/net/tests/TcpClient_reg1.cc | 29 ++ include/muduo/net/tests/TcpClient_reg2.cc | 30 ++ include/muduo/net/tests/TcpClient_reg3.cc | 24 + .../muduo/net/tests/TimerQueue_unittest.cc | 66 +++ .../muduo/net/tests/ZlibStream_unittest.cc | 91 ++++ 186 files changed, 17734 insertions(+), 1 deletion(-) create mode 100644 include/Telemeter.hpp create mode 100644 include/Type.hpp create mode 100644 include/Udp.hpp create mode 100644 include/boost/any.hpp create mode 100644 include/center/CenterConfig.txt create mode 100644 include/center/MirDescript.cpp create mode 100644 include/center/MirDescript.h create mode 100644 include/center/TcpEcho.cpp create mode 100644 include/center/TcpEcho.h create mode 100644 include/center/center.cpp create mode 100644 include/center/center.h create mode 100644 include/center/main.cpp create mode 100644 include/mirror/ClassInfo.h create mode 100644 include/mirror/Message.h create mode 100644 include/mirror/Mirror.h create mode 100644 include/mirror/MirrorConfig.txt create mode 100644 include/muduo/base/AsyncLogging.cc create mode 100644 include/muduo/base/AsyncLogging.h create mode 100644 include/muduo/base/Atomic.h create mode 100644 include/muduo/base/BUILD.bazel create mode 100644 include/muduo/base/BlockingQueue.h create mode 100644 include/muduo/base/BoundedBlockingQueue.h create mode 100644 include/muduo/base/CMakeLists.txt create mode 100644 include/muduo/base/Condition.cc create mode 100644 include/muduo/base/Condition.h create mode 100644 include/muduo/base/CountDownLatch.cc create mode 100644 include/muduo/base/CountDownLatch.h create mode 100644 include/muduo/base/CurrentThread.cc create mode 100644 include/muduo/base/CurrentThread.h create mode 100644 include/muduo/base/Date.cc create mode 100644 include/muduo/base/Date.h create mode 100644 include/muduo/base/Exception.cc create mode 100644 include/muduo/base/Exception.h create mode 100644 include/muduo/base/FileUtil.cc create mode 100644 include/muduo/base/FileUtil.h create mode 100644 include/muduo/base/GzipFile.h create mode 100644 include/muduo/base/LogFile.cc create mode 100644 include/muduo/base/LogFile.h create mode 100644 include/muduo/base/LogStream.cc create mode 100644 include/muduo/base/LogStream.h create mode 100644 include/muduo/base/Logging.cc create mode 100644 include/muduo/base/Logging.h create mode 100644 include/muduo/base/Mutex.h create mode 100644 include/muduo/base/ProcessInfo.cc create mode 100644 include/muduo/base/ProcessInfo.h create mode 100644 include/muduo/base/Singleton.h create mode 100644 include/muduo/base/StringPiece.h create mode 100644 include/muduo/base/Thread.cc create mode 100644 include/muduo/base/Thread.h create mode 100644 include/muduo/base/ThreadLocal.h create mode 100644 include/muduo/base/ThreadLocalSingleton.h create mode 100644 include/muduo/base/ThreadPool.cc create mode 100644 include/muduo/base/ThreadPool.h create mode 100644 include/muduo/base/TimeZone.cc create mode 100644 include/muduo/base/TimeZone.h create mode 100644 include/muduo/base/Timestamp.cc create mode 100644 include/muduo/base/Timestamp.h create mode 100644 include/muduo/base/Types.h create mode 100644 include/muduo/base/WeakCallback.h create mode 100644 include/muduo/base/copyable.h create mode 100644 include/muduo/base/noncopyable.h create mode 100644 include/muduo/base/tests/AsyncLogging_test.cc create mode 100644 include/muduo/base/tests/Atomic_unittest.cc create mode 100644 include/muduo/base/tests/BlockingQueue_bench.cc create mode 100644 include/muduo/base/tests/BlockingQueue_test.cc create mode 100644 include/muduo/base/tests/BoundedBlockingQueue_test.cc create mode 100644 include/muduo/base/tests/CMakeLists.txt create mode 100644 include/muduo/base/tests/Date_unittest.cc create mode 100644 include/muduo/base/tests/Exception_test.cc create mode 100644 include/muduo/base/tests/FileUtil_test.cc create mode 100644 include/muduo/base/tests/Fork_test.cc create mode 100644 include/muduo/base/tests/GzipFile_test.cc create mode 100644 include/muduo/base/tests/LogFile_test.cc create mode 100644 include/muduo/base/tests/LogStream_bench.cc create mode 100644 include/muduo/base/tests/LogStream_test.cc create mode 100644 include/muduo/base/tests/Logging_test.cc create mode 100644 include/muduo/base/tests/Mutex_test.cc create mode 100644 include/muduo/base/tests/ProcessInfo_test.cc create mode 100644 include/muduo/base/tests/SingletonThreadLocal_test.cc create mode 100644 include/muduo/base/tests/Singleton_test.cc create mode 100644 include/muduo/base/tests/ThreadLocalSingleton_test.cc create mode 100644 include/muduo/base/tests/ThreadLocal_test.cc create mode 100644 include/muduo/base/tests/ThreadPool_test.cc create mode 100644 include/muduo/base/tests/Thread_bench.cc create mode 100644 include/muduo/base/tests/Thread_test.cc create mode 100644 include/muduo/base/tests/TimeZone_unittest.cc create mode 100644 include/muduo/base/tests/Timestamp_unittest.cc create mode 100644 include/muduo/net/Acceptor.cc create mode 100644 include/muduo/net/Acceptor.h create mode 100644 include/muduo/net/BUILD.bazel create mode 100644 include/muduo/net/Buffer.cc create mode 100644 include/muduo/net/Buffer.h create mode 100644 include/muduo/net/CMakeLists.txt create mode 100644 include/muduo/net/Callbacks.h create mode 100644 include/muduo/net/Channel.cc create mode 100644 include/muduo/net/Channel.h create mode 100644 include/muduo/net/Connector.cc create mode 100644 include/muduo/net/Connector.h create mode 100644 include/muduo/net/Endian.h create mode 100644 include/muduo/net/EventLoop.cc create mode 100644 include/muduo/net/EventLoop.h create mode 100644 include/muduo/net/EventLoopThread.cc create mode 100644 include/muduo/net/EventLoopThread.h create mode 100644 include/muduo/net/EventLoopThreadPool.cc create mode 100644 include/muduo/net/EventLoopThreadPool.h create mode 100644 include/muduo/net/InetAddress.cc create mode 100644 include/muduo/net/InetAddress.h create mode 100644 include/muduo/net/Poller.cc create mode 100644 include/muduo/net/Poller.h create mode 100644 include/muduo/net/Socket.cc create mode 100644 include/muduo/net/Socket.h create mode 100644 include/muduo/net/SocketsOps.cc create mode 100644 include/muduo/net/SocketsOps.h create mode 100644 include/muduo/net/TcpClient.cc create mode 100644 include/muduo/net/TcpClient.h create mode 100644 include/muduo/net/TcpConnection.cc create mode 100644 include/muduo/net/TcpConnection.h create mode 100644 include/muduo/net/TcpServer.cc create mode 100644 include/muduo/net/TcpServer.h create mode 100644 include/muduo/net/Timer.cc create mode 100644 include/muduo/net/Timer.h create mode 100644 include/muduo/net/TimerId.h create mode 100644 include/muduo/net/TimerQueue.cc create mode 100644 include/muduo/net/TimerQueue.h create mode 100644 include/muduo/net/ZlibStream.h create mode 100644 include/muduo/net/boilerplate.cc create mode 100644 include/muduo/net/boilerplate.h create mode 100644 include/muduo/net/http/BUILD.bazel create mode 100644 include/muduo/net/http/CMakeLists.txt create mode 100644 include/muduo/net/http/HttpContext.cc create mode 100644 include/muduo/net/http/HttpContext.h create mode 100644 include/muduo/net/http/HttpRequest.h create mode 100644 include/muduo/net/http/HttpResponse.cc create mode 100644 include/muduo/net/http/HttpResponse.h create mode 100644 include/muduo/net/http/HttpServer.cc create mode 100644 include/muduo/net/http/HttpServer.h create mode 100644 include/muduo/net/http/tests/HttpRequest_unittest.cc create mode 100644 include/muduo/net/http/tests/HttpServer_test.cc create mode 100644 include/muduo/net/inspect/BUILD.bazel create mode 100644 include/muduo/net/inspect/CMakeLists.txt create mode 100644 include/muduo/net/inspect/Inspector.cc create mode 100644 include/muduo/net/inspect/Inspector.h create mode 100644 include/muduo/net/inspect/PerformanceInspector.cc create mode 100644 include/muduo/net/inspect/PerformanceInspector.h create mode 100644 include/muduo/net/inspect/ProcessInspector.cc create mode 100644 include/muduo/net/inspect/ProcessInspector.h create mode 100644 include/muduo/net/inspect/SystemInspector.cc create mode 100644 include/muduo/net/inspect/SystemInspector.h create mode 100644 include/muduo/net/inspect/tests/BUILD.bazel create mode 100644 include/muduo/net/inspect/tests/Inspector_test.cc create mode 100644 include/muduo/net/poller/DefaultPoller.cc create mode 100644 include/muduo/net/poller/EPollPoller.cc create mode 100644 include/muduo/net/poller/EPollPoller.h create mode 100644 include/muduo/net/poller/PollPoller.cc create mode 100644 include/muduo/net/poller/PollPoller.h create mode 100644 include/muduo/net/protobuf/BufferStream.h create mode 100644 include/muduo/net/protobuf/CMakeLists.txt create mode 100644 include/muduo/net/protobuf/ProtobufCodecLite.cc create mode 100644 include/muduo/net/protobuf/ProtobufCodecLite.h create mode 100644 include/muduo/net/protorpc/CMakeLists.txt create mode 100644 include/muduo/net/protorpc/README create mode 100644 include/muduo/net/protorpc/RpcChannel.cc create mode 100644 include/muduo/net/protorpc/RpcChannel.h create mode 100644 include/muduo/net/protorpc/RpcCodec.cc create mode 100644 include/muduo/net/protorpc/RpcCodec.h create mode 100644 include/muduo/net/protorpc/RpcCodec_test.cc create mode 100644 include/muduo/net/protorpc/RpcServer.cc create mode 100644 include/muduo/net/protorpc/RpcServer.h create mode 100644 include/muduo/net/protorpc/google-inl.h create mode 100644 include/muduo/net/protorpc/rpc.proto create mode 100644 include/muduo/net/protorpc/rpcservice.proto create mode 100644 include/muduo/net/tests/Buffer_unittest.cc create mode 100644 include/muduo/net/tests/CMakeLists.txt create mode 100644 include/muduo/net/tests/Channel_test.cc create mode 100644 include/muduo/net/tests/EchoClient_unittest.cc create mode 100644 include/muduo/net/tests/EchoServer_unittest.cc create mode 100644 include/muduo/net/tests/EventLoopThreadPool_unittest.cc create mode 100644 include/muduo/net/tests/EventLoopThread_unittest.cc create mode 100644 include/muduo/net/tests/EventLoop_unittest.cc create mode 100644 include/muduo/net/tests/InetAddress_unittest.cc create mode 100644 include/muduo/net/tests/TcpClient_reg1.cc create mode 100644 include/muduo/net/tests/TcpClient_reg2.cc create mode 100644 include/muduo/net/tests/TcpClient_reg3.cc create mode 100644 include/muduo/net/tests/TimerQueue_unittest.cc create mode 100644 include/muduo/net/tests/ZlibStream_unittest.cc diff --git a/.gitignore b/.gitignore index 3f0d827..f77e472 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ build/ lib/ -include/ diff --git a/include/Telemeter.hpp b/include/Telemeter.hpp new file mode 100644 index 0000000..66ea08f --- /dev/null +++ b/include/Telemeter.hpp @@ -0,0 +1,91 @@ +#ifndef SRC_TELEMETER_H +#define SRC_TELEMETER_H + +#pragma once + +#include +#include + +enum class LoadLevel : uint8_t +{ + untapped = 0, //no client dispatched on this mirror + light = 1, //[0% - 50%] + medium = 2, //[50% - 80%] + heavy = 3, //[ >= 80%] +}; + + +//POD type +struct DetailLoadState +{ + uint8_t mem_load, serve_load, net_load_, reserve_seg_; +}; + +void copy(DetailLoadState* dest, const DetailLoadState* sour) +{ memcpy(dest, sour, sizeof(DetailLoadState)); } + +#ifdef SRC_CENTER_H +//center的setting, POD type +struct Setting +{ + uint8_t mir_load_record_interval_; //记录mirror负载到缓存的间隔(按照心跳包的个数来计数), 从配置文件中读 + uint8_t mir_dblog_interval_; //将mirror负载缓存更新到数据库(数据文件)的间隔(缓存了这么多之后打一次log), 从配置文件中读 + uint8_t mir_max_disbeat_time_; //多少个心跳轮无心跳视为断线 + uint8_t cli_login_cache_time_; //清空一个cli登录缓冲的时间 +}; +//第一字段为60表示一分钟(60个心跳包)记录一次mir的负载情况, +//第二字段为5表示5分钟(缓存5次)输出到遥测数据库一次 + +const constexpr uint _permanent_thread_num_ = 3; //center的常驻线程数量 + +#endif + +#ifdef SRC_MIRROR_H +//mirror的setting, POD type +struct Setting +{ + int center_ip_; + //int backup_center_ip_; + uint8_t mir_beat_interval_; + uint8_t //数据库ip? +}; + +#endif + +#define RESERVE_SEGMENG_INIT_VALUE 0 + +namespace telemeter +{ + const constexpr char* klog_file = "TelemeterLog.txt"; //临时的遥测日志文件 + +#ifdef SRC_CENTER_H + //双缓冲配置表解决一写多读线程安全问题 + Setting _set_cache_one = {60, 5, 15, 60}; + Setting _set_cache_two = {60, 5, 15, 60}; + //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 + Setting* setting = &_set_cache_one; + Setting* setting_copy = &_set_cache_two; +#endif + +#ifdef SRC_MIRROR_H +#endif + + + + + //获取本机负载情况的函数, 需要统计空闲内存占比, cpu负载, 空闲磁盘占比 + LoadLevel getLocalLoadLevel(); + + //int getLocalMemLoad(); + //int getLocalSevLoad(); + //int getLocalNetLoad(); +} + + + + + + + + +#endif //SRC_TELEMETER_H \ No newline at end of file diff --git a/include/Type.hpp b/include/Type.hpp new file mode 100644 index 0000000..65ed292 --- /dev/null +++ b/include/Type.hpp @@ -0,0 +1,12 @@ +#ifndef SRC_TYPE_H +#define SRC_TYPE_H + +#pragma once + +#include "boost/lockfree/queue.hpp" +template +using lfqueue = boost::lockfree::queue; + + + +#endif //SRC_TYPE_H \ No newline at end of file diff --git a/include/Udp.hpp b/include/Udp.hpp new file mode 100644 index 0000000..978aae0 --- /dev/null +++ b/include/Udp.hpp @@ -0,0 +1,53 @@ +#ifndef SRC_UDP_H +#define SRC_UDP_H + +#pragma once + +//暂时以int表示ip, 有需要则封装成类 +using IP = int; + +namespace port +{ + const constexpr int kCLI_LOGIN_ = 20800; + const constexpr int kCLI_BEAT_ = 20801; + const constexpr int kMIR_BEAT_ = 20802; + const constexpr int kINS_MSG_ = 20803; +} + +namespace udp +{ + void loop(); + + void recv(); + void send(); +} + + +#endif //SRC_UDP_H + + + +/* +class IP +{ +private: + union //IP地址共占4个字节 + { + struct //这是一个由4个字节构成的匿名结构体 + { + unsigned char seg0; + unsigned char seg1; + unsigned char seg2; + unsigned char seg3; + }; //4字节的IP地址可以看作4部分,每部分1字节 + unsigned int address; //4字节的IP地址可以看成一个4字节的整体 + }; +public: + IP(int=0,int=0,int=0,int=0); //构造函数 + void showIP(); //用四段法显示IP地址 + bool sameSubnet(const IP &ip, const IP &mark); //判断是否处于同一子网 + char whatKind(); //返回属于哪一类网络 +}; + +原文链接:https://blog.csdn.net/chongshangyunxiao321/article/details/51055658 +*/ diff --git a/include/boost/any.hpp b/include/boost/any.hpp new file mode 100644 index 0000000..9c2789c --- /dev/null +++ b/include/boost/any.hpp @@ -0,0 +1,342 @@ +// See http://www.boost.org/libs/any for Documentation. + +#ifndef BOOST_ANY_INCLUDED +#define BOOST_ANY_INCLUDED + +#if defined(_MSC_VER) +# pragma once +#endif + +// what: variant type boost::any +// who: contributed by Kevlin Henney, +// with features contributed and bugs found by +// Antony Polukhin, Ed Brey, Mark Rodgers, +// Peter Dimov, and James Curran +// when: July 2001, April 2013 - 2020 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + class any + { + public: // structors + + BOOST_CONSTEXPR any() BOOST_NOEXCEPT + : content(0) + { + } + + template + any(const ValueType & value) + : content(new holder< + BOOST_DEDUCED_TYPENAME remove_cv::type>::type + >(value)) + { + } + + any(const any & other) + : content(other.content ? other.content->clone() : 0) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Move constructor + any(any&& other) BOOST_NOEXCEPT + : content(other.content) + { + other.content = 0; + } + + // Perfect forwarding of ValueType + template + any(ValueType&& value + , typename boost::disable_if >::type* = 0 // disable if value has type `any&` + , typename boost::disable_if >::type* = 0) // disable if value has type `const ValueType&&` + : content(new holder< typename decay::type >(static_cast(value))) + { + } +#endif + + ~any() BOOST_NOEXCEPT + { + delete content; + } + + public: // modifiers + + any & swap(any & rhs) BOOST_NOEXCEPT + { + placeholder* tmp = content; + content = rhs.content; + rhs.content = tmp; + return *this; + } + + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template + any & operator=(const ValueType & rhs) + { + any(rhs).swap(*this); + return *this; + } + + any & operator=(any rhs) + { + rhs.swap(*this); + return *this; + } + +#else + any & operator=(const any& rhs) + { + any(rhs).swap(*this); + return *this; + } + + // move assignment + any & operator=(any&& rhs) BOOST_NOEXCEPT + { + rhs.swap(*this); + any().swap(rhs); + return *this; + } + + // Perfect forwarding of ValueType + template + any & operator=(ValueType&& rhs) + { + any(static_cast(rhs)).swap(*this); + return *this; + } +#endif + + public: // queries + + bool empty() const BOOST_NOEXCEPT + { + return !content; + } + + void clear() BOOST_NOEXCEPT + { + any().swap(*this); + } + + const boost::typeindex::type_info& type() const BOOST_NOEXCEPT + { + return content ? content->type() : boost::typeindex::type_id().type_info(); + } + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + private: // types +#else + public: // types (public so any_cast can be non-friend) +#endif + + class BOOST_SYMBOL_VISIBLE placeholder + { + public: // structors + + virtual ~placeholder() + { + } + + public: // queries + + virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0; + + virtual placeholder * clone() const = 0; + + }; + + template + class holder +#ifndef BOOST_NO_CXX11_FINAL + final +#endif + : public placeholder + { + public: // structors + + holder(const ValueType & value) + : held(value) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + holder(ValueType&& value) + : held(static_cast< ValueType&& >(value)) + { + } +#endif + public: // queries + + const boost::typeindex::type_info& type() const BOOST_NOEXCEPT BOOST_OVERRIDE + { + return boost::typeindex::type_id().type_info(); + } + + placeholder * clone() const BOOST_OVERRIDE + { + return new holder(held); + } + + public: // representation + + ValueType held; + + private: // intentionally left unimplemented + holder & operator=(const holder &); + }; + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + + private: // representation + + template + friend ValueType * any_cast(any *) BOOST_NOEXCEPT; + + template + friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT; + +#else + + public: // representation (public so any_cast can be non-friend) + +#endif + + placeholder * content; + + }; + + inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + class BOOST_SYMBOL_VISIBLE bad_any_cast : +#ifndef BOOST_NO_RTTI + public std::bad_cast +#else + public std::exception +#endif + { + public: + const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE + { + return "boost::bad_any_cast: " + "failed conversion using boost::any_cast"; + } + }; + + template + ValueType * any_cast(any * operand) BOOST_NOEXCEPT + { + return operand && operand->type() == boost::typeindex::type_id() + ? boost::addressof( + static_cast::type> *>(operand->content)->held + ) + : 0; + } + + template + inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT + { + return any_cast(const_cast(operand)); + } + + template + ValueType any_cast(any & operand) + { + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + + + nonref * result = any_cast(boost::addressof(operand)); + if(!result) + boost::throw_exception(bad_any_cast()); + + // Attempt to avoid construction of a temporary object in cases when + // `ValueType` is not a reference. Example: + // `static_cast(*result);` + // which is equal to `std::string(*result);` + typedef BOOST_DEDUCED_TYPENAME boost::conditional< + boost::is_reference::value, + ValueType, + BOOST_DEDUCED_TYPENAME boost::add_reference::type + >::type ref_type; + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4172) // "returning address of local variable or temporary" but *result is not local! +#endif + return static_cast(*result); +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + } + + template + inline ValueType any_cast(const any & operand) + { + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + return any_cast(const_cast(operand)); + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + inline ValueType any_cast(any&& operand) + { + BOOST_STATIC_ASSERT_MSG( + boost::is_rvalue_reference::value /*true if ValueType is rvalue or just a value*/ + || boost::is_const< typename boost::remove_reference::type >::value, + "boost::any_cast shall not be used for getting nonconst references to temporary objects" + ); + return any_cast(operand); + } +#endif + + + // Note: The "unsafe" versions of any_cast are not part of the + // public interface and may be removed at any time. They are + // required where we know what type is stored in the any and can't + // use typeid() comparison, e.g., when our types may travel across + // different shared libraries. + template + inline ValueType * unsafe_any_cast(any * operand) BOOST_NOEXCEPT + { + return boost::addressof( + static_cast *>(operand->content)->held + ); + } + + template + inline const ValueType * unsafe_any_cast(const any * operand) BOOST_NOEXCEPT + { + return unsafe_any_cast(const_cast(operand)); + } +} + +// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. +// Copyright Antony Polukhin, 2013-2020. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#endif diff --git a/include/center/CenterConfig.txt b/include/center/CenterConfig.txt new file mode 100644 index 0000000..cdb0999 --- /dev/null +++ b/include/center/CenterConfig.txt @@ -0,0 +1,48 @@ +next_read_this_file_interval: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) + +mir_load_record_interval: [60] //多少次收到心跳包后记录一次mirror的负载情况 +mir_load_dblog_interval: [5] //多少次记录后, 一次性输出到遥测数据库 +mir_max_disbeat_time: [15] //该数字乘上心跳间隔表示多少秒钟无心跳视为断线, 最大128 +cli_login_cache_time: [60]s //多少秒内收到重复的cli登录请求视为包延迟到达 + +变量命名:参照muduo库, + 类型名都是大写开头驼峰命名 + 类内函数名都是小写开头驼峰命名 + 变量名都以小写字母下划线命名 + 类内变量都额外加一个下划线结尾 + 常量额外以k开头 + 希望对外匿名的变量以下划线开头 + +建议:全局函数除了一个单词能表明含义的情况均以大写字母开头的驼峰命名 + +center启动流程 + 读取配置文件, 读入各项数据到内存中, 没有配置文件则用默认值{60, 5, 60, 0}初始化 + 提交任务: + 1.定时读取配置文件给telemeter的备份缓冲setting, 读取完成后交换主备份setting指针的值 + 2.开启3个 udp线程加入到线程池, 1. 收cli登录信息并回复, 调度算法在这里 2. 收mir心跳 3.收即时消息 + 3.loop启动 + 4.可能需要链接数据库 + 5.定时(每天0点)清空所有cli_ip和树形结构中的信息(类似重启), 触发条件是每晚各种东西都会断电掉线, 否则不需要 + +cli登录流程: + cli发送udp给center的20800端口 + ->center在cookie[无锁队列]中检查有无历史登录痕迹[读] + ->有:视为包延迟到达, 不做处理 + ->无:回复当前可用mirr地址[即all_mir], 在all_cli[哈希表]中查询是否出现过该UUID + //{如果把以下两行的任务改为提交给线程池执行而不在io线程, 在多个cli短时间内一同登录时可能会出现同时写的问题?} + ->有:说明是今日重新连接, 在mirs_data中校正该ip所分配mir的信息, 需要遍历并且修改 + ->无:说明是今天首次连接, 在mirs_data中记录该数据 + ->在队列尾部新加入该缓冲, 设置cli_login_cache_pop_interval后pop掉队头的任务 + ->输出日志, 包括cli_iD, timestamp, mir_ip, + +mir登录及心跳流程: + center在20802接受到mir心跳的udp包, 该函数有一个静态变量all_beat_count_ + ->在mirs_data中检查有无这个mir的ip + ->无, 是新的mir登录, 在mirs_data中记录该数据, 创建新的mirDescript, 标记其状态为untapped, beat_count = + ->有, 是mir的心跳, 给该mirror的beat_重置为mir_max_disbeat_time, 记录负载情况到load_cache, 同时给all_beat_count+1, 判断此时all_beat_count的值, 若其 >= mirs_data.size() - 1 + ->是, 给mirs_data中每一个value的beat_count - 1, 判断此时 - 1 之后的beat_count == 0 ? 是则说明掉线, 不是则说明正常, 记录负载情况到load_cache中, 如果load_cache满则一次写入数据库并清空 + //缺点在于一次掉线多个... + +message流程 + center在20803收到message的心跳包(一个布尔量), 给mirs_data内所有key发送一个布尔量, 完成 + diff --git a/include/center/MirDescript.cpp b/include/center/MirDescript.cpp new file mode 100644 index 0000000..e69de29 diff --git a/include/center/MirDescript.h b/include/center/MirDescript.h new file mode 100644 index 0000000..390ee7a --- /dev/null +++ b/include/center/MirDescript.h @@ -0,0 +1,40 @@ +#ifndef SRC_CENTER_MIRDESPCRIPT_H +#define SRC_CENTER_MIRDESPCRIPT_H + +#pragma once + +#include "Telemeter.hpp" +#include "Udp.hpp" + +#include +#include +#include + +class MirDescript : public boost::noncopyable +{ + private: + uint8_t beat_; //心跳次数计数, 用于 + LoadLevel load_level_; //粗略描述负载情况 + DetailLoadState load_state_; //详细负载情况todo: memcpy(this_state, mir_descript.load_state_) + std::unordered_set cli_ips_; //当前负责的cli_ip为了O(1)查找 + std::vector load_cache_; //记录过去一段时间mir负载的缓冲 + + public: + static const constexpr int noexist = -1; + + public: + uint getBeat() const { return static_cast(beat_); } + void resetBeat(uint max_disbeat) { assert(max_disbeat <= 128), this->beat_ = max_disbeat; } + LoadLevel getRoughLoad() const { return this->load_level_; } + void setLoadState(DetailLoadState&& load) { copy(&(this->load_state_), &load); } + auto contains(IP cli_ip) { return auto index = this->cli_ips_.find(cli_ip), index == std::end(this->cli_ips_) ? noexist : index; } + + +}; + + + + + + +#endif //SRC_CENTER_MIRDESPCRIPT_H \ No newline at end of file diff --git a/include/center/TcpEcho.cpp b/include/center/TcpEcho.cpp new file mode 100644 index 0000000..6620634 --- /dev/null +++ b/include/center/TcpEcho.cpp @@ -0,0 +1,40 @@ +#include "TcpEcho.h" + +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; + +//using namespace muduo; +//using namespace muduo::net; + +EchoServer::EchoServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr) + : server_(loop, listenAddr, "EchoServer") +{ + server_.setConnectionCallback( + std::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + std::bind(&EchoServer::onMessage, this, _1, _2, _3)); +} + +void EchoServer::start() +{ + server_.start(); +} + +void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn) +{ +// LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> " +// << conn->localAddress().toIpPort() << " is " +// << (conn->connected() ? "UP" : "DOWN"); +} + +void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time) +{ +// muduo::string msg(buf->retrieveAllAsString()); +// LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, " +// << "data received at " << time.toString(); +// conn->send(msg); +} diff --git a/include/center/TcpEcho.h b/include/center/TcpEcho.h new file mode 100644 index 0000000..7a9dab7 --- /dev/null +++ b/include/center/TcpEcho.h @@ -0,0 +1,24 @@ +#ifndef SRC_CENTER_TCPECHO_H +#define SRC_CENTER_TCPECHO_H +#include "muduo/net/TcpServer.h" + + +class EchoServer +{ + public: + EchoServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr); + + void start(); // calls server_.start(); + + private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); + + muduo::net::TcpServer server_; +}; + +#endif //SRC_CENTER_TCPECHO_H \ No newline at end of file diff --git a/include/center/center.cpp b/include/center/center.cpp new file mode 100644 index 0000000..c887a49 --- /dev/null +++ b/include/center/center.cpp @@ -0,0 +1,84 @@ +#include "center.h" + +void center::start() +{ + //假设udp namespace 下的 recv和send已经正常 + //任务队列最大数量 + pool_.setMaxQueueSize(30); + pool_.start(_permanent_thread_num_ + 5); //这里默认四核八线程, 也可以用std::hard_ware_concurrency()确定 + + //提交定时读取配置文件的任务,监听cli登录, mir心跳的任务 + this->pool_.run( [this](){ read_config(); }); + this->pool_.run( [this](){ wait_cli_login(); }); + this->pool_.run( [this](){ listen_mir_beat(); }); + //this->pool.run( [this](){ clear_mirs_data(); }); + + //可能需要设置一段时间内进行日志输出的文件和文件路径 + +} + +void center::read_config() +{ + //或者放到center中作为一个变量 + static std::string config_file_path; + //或者 + //static std::fstream config_file; + + //可以使用如下形式的定义 + //static auto read_data_infile/copy/swap = [=](...){ ... }; + + while(true) + { + Setting set_in_file{}; + + //读取配置文件 + //read_data_in(config_file_path, set_in_file); + + //复制到配置副本中 + //copy(set_in_file, *setting_copy); + + //交换主副配置指针 + //swap(setting_copy, setting); //atomic operation + + //sleep(set_in_file.next_read_intrerval); + } +} + +void center::wait_cli_login() +{ + //用于接收数据的缓冲区 + //char* buffer[xxx_len]; + //flush(buffer) + //current_available_mir + + while(true) + { + //udp::recv(port, buffer ...); + + //按照协议格式进行解析, 并且得到ip等其他信息 + //auto [cli_id, login_count, state] = msg[...] + + //登录或者重新连接 + // if(!cookie_.contains(cli_id)) + // { + // //重新连接 + // if(all_cli_.contains(cli_id)) + // { + // correct_info(mirs_data_, cli_id); + // } + // else //首次链接 + // { + // record_info(mirs_data, cli_id); + // } + // cookie_.cache_login_info(cli_id); + // dblog(cli_login_event, cli_id); + // } + // else + // { + // //延迟到达不做处理 + // continue; + // } + // flush(buffer); + } +} + diff --git a/include/center/center.h b/include/center/center.h new file mode 100644 index 0000000..9e6158e --- /dev/null +++ b/include/center/center.h @@ -0,0 +1,46 @@ +#ifndef SRC_CENTER_H +#define SRC_CENTER_H + +#include "muduo/base/ThreadPool.h" + +#include "Udp.hpp" +#include "Telemeter.hpp" +#include "../Type.hpp" //lock free queue -> lfqueue + +#include "MirDescript.h" + +#include + +class center +{ +private: + //O(1)查找所有可用的mirip地址, [不再]初始化时从db中取出预存, [而是]从心跳包中分析即可, 心跳包最后一段表示当前连接数[处理mirror连接情况与center缓存数据不一致的问题] + //记录树形mir->cli信息的数据结构, list? hash_table?, 需要缓存mir负载信息以供调度算法使用? + //一种变量, 记录过去一段时间每个mir的平均负载情况, 定时更新到遥测数据库里 + using uuid = size_t; + std::set all_cli_; //查找频繁, 不从mirs_data中遍历, 额外保存 + std::unordered_map mirs_data_; //记录信息的树形结构 + lfqueue cookie_; //记录最近登陆过的cli缓冲 + muduo::ThreadPool pool_; //线程池 + +private: + //center start: + + //读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 + void read_config(); + + //开启监听cli登录的udp线程, 每隔几十次登录调用一次负载均衡分配算法更改当前的current_available_mir + void wait_cli_login(); + + //开启收听mir心跳的udp线程, mir心跳断线的算法在这里实现, 记录最近一段时间遥测信息的算法也在这里, + void listen_mir_beat(); + + //定时清空登录信息的算法, 例如每晚十二点, + void clear_mirs_data(); + +public: + + void start(); +}; + +#endif //SRC_CENTER_H \ No newline at end of file diff --git a/include/center/main.cpp b/include/center/main.cpp new file mode 100644 index 0000000..a2d2b42 --- /dev/null +++ b/include/center/main.cpp @@ -0,0 +1,22 @@ + + +#include "TcpEcho.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" + +#include + +// using namespace muduo; +// using namespace muduo::net; + +int main() +{ + LOG_INFO << "pid = " << getpid(); + muduo::net::EventLoop loop; + muduo::net::InetAddress listenAddr(2007); + EchoServer server(&loop, listenAddr); + + server.start(); + loop.loop(); +} diff --git a/include/mirror/ClassInfo.h b/include/mirror/ClassInfo.h new file mode 100644 index 0000000..45c475a --- /dev/null +++ b/include/mirror/ClassInfo.h @@ -0,0 +1,12 @@ +#ifndef SRC_MIRROR_CLIDESCRIPT_H +#define SRC_MIRROR_CLIDESCRIPT_H + +#pragma once + +#include + +//暂时以string代表课程信息 +using ClassInfo = std::string; +//classinfo中应该有一个bool量表示是否发送过, 发送过置否, 每次更新置真 + +#endif //SRC_MIRROR_CLIDESCRIPT_H diff --git a/include/mirror/Message.h b/include/mirror/Message.h new file mode 100644 index 0000000..8d7ca31 --- /dev/null +++ b/include/mirror/Message.h @@ -0,0 +1,22 @@ +#ifndef SRC_MIRROR_MESSAGE_H +#define SRC_MIRROR_MESSAGE_H + +#pragma once + +#include "../Udp.hpp" + +#include +#include +#include + +//暂时以string代表message的内容 +using Content = std::string; + +class Message +{ + private: + Content content_; //消息内容 + std::unordered_set dest_; //需要收到消息的目标 +}; + +#endif //SRC_MIRROR_MESSAGE_H diff --git a/include/mirror/Mirror.h b/include/mirror/Mirror.h new file mode 100644 index 0000000..328c374 --- /dev/null +++ b/include/mirror/Mirror.h @@ -0,0 +1,33 @@ +#ifndef SRC_MIRROR_MIRROR_H +#define SRC_MIRROR_MIRROR_H + + +#include "muduo/base/ThreadPool.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/TcpServer.h" +#include "muduo/net/EventLoop.h" + +#include "../Telemeter.hpp" +#include "../Type.hpp" //lock free queue -> lfqueue + +#include "ClassInfo.h" +#include "Message.h" + +#include +#include + +class Mirror +{ + private: + DetailLoadState load_; + std::queue mesages_; + std::unordered_map clis_data_; + lfqueue> cookie_; + + muduo::net::EventLoop loop_; + muduo::net::TcpServer server_; + muduo::ThreadPool pool_; +}; + + +#endif //SRC_MIRROR_MIRROR_H \ No newline at end of file diff --git a/include/mirror/MirrorConfig.txt b/include/mirror/MirrorConfig.txt new file mode 100644 index 0000000..3d96c48 --- /dev/null +++ b/include/mirror/MirrorConfig.txt @@ -0,0 +1,22 @@ +next_read_this_file_interval: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) + +mir_heart_beat_interval: [1]s //心跳的间隔 +mir_load_report_interval: [60] //多少个心跳包后更新负载情况 +cli_class_info_cache_time: [600]s //课程信息在cli断联后缓存时间, 如果内存紧张可以适当缩短 + +mir启动流程 + 启动EventLoop, 启动Server, 清空clis_data + 提交任务 + 定时读取配置文件 + 按照更新负载情况的间隔更新load + 心跳任务, 心跳计数器的值从配置表中读取 + 启动等待即时消息的线程 + +cli通过tcp连接 + ->连接:从cookie中寻找缓存, 若无则在clis_data中更新其信息, 从数据库拉取课表信息, 并根据课表信息提交一段时间后重新拉取下节课的任务 + ->断线:将clis_data的信息存入缓存, 设置 +Message + 使用者通过管理程序向数据库中插入即时消息的内容和目的地, 然后发送一个简短报文给center, center收到后 +发送udp包给mir, mir接收到包在数据库中读取消息内容和消息目的地和消息过期时间, 将前两者插入到消息队列中并设置定时清空队头的任务 + +//可能的每晚清空新奇重新启动? 有cli彻夜开着吗? diff --git a/include/muduo/base/AsyncLogging.cc b/include/muduo/base/AsyncLogging.cc new file mode 100644 index 0000000..0f82444 --- /dev/null +++ b/include/muduo/base/AsyncLogging.cc @@ -0,0 +1,136 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/AsyncLogging.h" +#include "muduo/base/LogFile.h" +#include "muduo/base/Timestamp.h" + +#include + +using namespace muduo; + +AsyncLogging::AsyncLogging(const string& basename, + off_t rollSize, + int flushInterval) + : flushInterval_(flushInterval), + running_(false), + basename_(basename), + rollSize_(rollSize), + thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"), + latch_(1), + mutex_(), + cond_(mutex_), + currentBuffer_(new Buffer), + nextBuffer_(new Buffer), + buffers_() +{ + currentBuffer_->bzero(); + nextBuffer_->bzero(); + buffers_.reserve(16); +} + +void AsyncLogging::append(const char* logline, int len) +{ + muduo::MutexLockGuard lock(mutex_); + if (currentBuffer_->avail() > len) + { + currentBuffer_->append(logline, len); + } + else + { + buffers_.push_back(std::move(currentBuffer_)); + + if (nextBuffer_) + { + currentBuffer_ = std::move(nextBuffer_); + } + else + { + currentBuffer_.reset(new Buffer); // Rarely happens + } + currentBuffer_->append(logline, len); + cond_.notify(); + } +} + +void AsyncLogging::threadFunc() +{ + assert(running_ == true); + latch_.countDown(); + LogFile output(basename_, rollSize_, false); + BufferPtr newBuffer1(new Buffer); + BufferPtr newBuffer2(new Buffer); + newBuffer1->bzero(); + newBuffer2->bzero(); + BufferVector buffersToWrite; + buffersToWrite.reserve(16); + while (running_) + { + assert(newBuffer1 && newBuffer1->length() == 0); + assert(newBuffer2 && newBuffer2->length() == 0); + assert(buffersToWrite.empty()); + + { + muduo::MutexLockGuard lock(mutex_); + if (buffers_.empty()) // unusual usage! + { + cond_.waitForSeconds(flushInterval_); + } + buffers_.push_back(std::move(currentBuffer_)); + currentBuffer_ = std::move(newBuffer1); + buffersToWrite.swap(buffers_); + if (!nextBuffer_) + { + nextBuffer_ = std::move(newBuffer2); + } + } + + assert(!buffersToWrite.empty()); + + if (buffersToWrite.size() > 25) + { + char buf[256]; + snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n", + Timestamp::now().toFormattedString().c_str(), + buffersToWrite.size()-2); + fputs(buf, stderr); + output.append(buf, static_cast(strlen(buf))); + buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end()); + } + + for (const auto& buffer : buffersToWrite) + { + // FIXME: use unbuffered stdio FILE ? or use ::writev ? + output.append(buffer->data(), buffer->length()); + } + + if (buffersToWrite.size() > 2) + { + // drop non-bzero-ed buffers, avoid trashing + buffersToWrite.resize(2); + } + + if (!newBuffer1) + { + assert(!buffersToWrite.empty()); + newBuffer1 = std::move(buffersToWrite.back()); + buffersToWrite.pop_back(); + newBuffer1->reset(); + } + + if (!newBuffer2) + { + assert(!buffersToWrite.empty()); + newBuffer2 = std::move(buffersToWrite.back()); + buffersToWrite.pop_back(); + newBuffer2->reset(); + } + + buffersToWrite.clear(); + output.flush(); + } + output.flush(); +} + diff --git a/include/muduo/base/AsyncLogging.h b/include/muduo/base/AsyncLogging.h new file mode 100644 index 0000000..46e77dd --- /dev/null +++ b/include/muduo/base/AsyncLogging.h @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_ASYNCLOGGING_H +#define MUDUO_BASE_ASYNCLOGGING_H + +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/BoundedBlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/LogStream.h" + +#include +#include + +namespace muduo +{ + +class AsyncLogging : noncopyable +{ + public: + + AsyncLogging(const string& basename, + off_t rollSize, + int flushInterval = 3); + + ~AsyncLogging() + { + if (running_) + { + stop(); + } + } + + void append(const char* logline, int len); + + void start() + { + running_ = true; + thread_.start(); + latch_.wait(); + } + + void stop() NO_THREAD_SAFETY_ANALYSIS + { + running_ = false; + cond_.notify(); + thread_.join(); + } + + private: + + void threadFunc(); + + typedef muduo::detail::FixedBuffer Buffer; + typedef std::vector> BufferVector; + typedef BufferVector::value_type BufferPtr; + + const int flushInterval_; + std::atomic running_; + const string basename_; + const off_t rollSize_; + muduo::Thread thread_; + muduo::CountDownLatch latch_; + muduo::MutexLock mutex_; + muduo::Condition cond_ GUARDED_BY(mutex_); + BufferPtr currentBuffer_ GUARDED_BY(mutex_); + BufferPtr nextBuffer_ GUARDED_BY(mutex_); + BufferVector buffers_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_ASYNCLOGGING_H diff --git a/include/muduo/base/Atomic.h b/include/muduo/base/Atomic.h new file mode 100644 index 0000000..6158fac --- /dev/null +++ b/include/muduo/base/Atomic.h @@ -0,0 +1,97 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_ATOMIC_H +#define MUDUO_BASE_ATOMIC_H + +#include "muduo/base/noncopyable.h" + +#include + +namespace muduo +{ + +namespace detail +{ +template +class AtomicIntegerT : noncopyable +{ + public: + AtomicIntegerT() + : value_(0) + { + } + + // uncomment if you need copying and assignment + // + // AtomicIntegerT(const AtomicIntegerT& that) + // : value_(that.get()) + // {} + // + // AtomicIntegerT& operator=(const AtomicIntegerT& that) + // { + // getAndSet(that.get()); + // return *this; + // } + + T get() + { + // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST) + return __sync_val_compare_and_swap(&value_, 0, 0); + } + + T getAndAdd(T x) + { + // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST) + return __sync_fetch_and_add(&value_, x); + } + + T addAndGet(T x) + { + return getAndAdd(x) + x; + } + + T incrementAndGet() + { + return addAndGet(1); + } + + T decrementAndGet() + { + return addAndGet(-1); + } + + void add(T x) + { + getAndAdd(x); + } + + void increment() + { + incrementAndGet(); + } + + void decrement() + { + decrementAndGet(); + } + + T getAndSet(T newValue) + { + // in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST) + return __sync_lock_test_and_set(&value_, newValue); + } + + private: + volatile T value_; +}; +} // namespace detail + +typedef detail::AtomicIntegerT AtomicInt32; +typedef detail::AtomicIntegerT AtomicInt64; + +} // namespace muduo + +#endif // MUDUO_BASE_ATOMIC_H diff --git a/include/muduo/base/BUILD.bazel b/include/muduo/base/BUILD.bazel new file mode 100644 index 0000000..48b598f --- /dev/null +++ b/include/muduo/base/BUILD.bazel @@ -0,0 +1,23 @@ +cc_library( + name = "base", + srcs = [ + "AsyncLogging.cc", + "Condition.cc", + "CountDownLatch.cc", + "CurrentThread.cc", + "Date.cc", + "Exception.cc", + "FileUtil.cc", + "LogFile.cc", + "LogStream.cc", + "Logging.cc", + "ProcessInfo.cc", + "Thread.cc", + "ThreadPool.cc", + "TimeZone.cc", + "Timestamp.cc", + ], + hdrs = glob(["*.h"]), + linkopts = ["-pthread"], + visibility = ["//visibility:public"], +) diff --git a/include/muduo/base/BlockingQueue.h b/include/muduo/base/BlockingQueue.h new file mode 100644 index 0000000..407c012 --- /dev/null +++ b/include/muduo/base/BlockingQueue.h @@ -0,0 +1,72 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_BLOCKINGQUEUE_H +#define MUDUO_BASE_BLOCKINGQUEUE_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +#include +#include + +namespace muduo +{ + +template +class BlockingQueue : noncopyable +{ + public: + BlockingQueue() + : mutex_(), + notEmpty_(mutex_), + queue_() + { + } + + void put(const T& x) + { + MutexLockGuard lock(mutex_); + queue_.push_back(x); + notEmpty_.notify(); // wait morphing saves us + // http://www.domaigne.com/blog/computing/condvars-signal-with-mutex-locked-or-not/ + } + + void put(T&& x) + { + MutexLockGuard lock(mutex_); + queue_.push_back(std::move(x)); + notEmpty_.notify(); + } + + T take() + { + MutexLockGuard lock(mutex_); + // always use a while-loop, due to spurious wakeup + while (queue_.empty()) + { + notEmpty_.wait(); + } + assert(!queue_.empty()); + T front(std::move(queue_.front())); + queue_.pop_front(); + return front; + } + + size_t size() const + { + MutexLockGuard lock(mutex_); + return queue_.size(); + } + + private: + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + std::deque queue_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_BLOCKINGQUEUE_H diff --git a/include/muduo/base/BoundedBlockingQueue.h b/include/muduo/base/BoundedBlockingQueue.h new file mode 100644 index 0000000..cfb4d3b --- /dev/null +++ b/include/muduo/base/BoundedBlockingQueue.h @@ -0,0 +1,101 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H +#define MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +#include +#include + +namespace muduo +{ + +template +class BoundedBlockingQueue : noncopyable +{ + public: + explicit BoundedBlockingQueue(int maxSize) + : mutex_(), + notEmpty_(mutex_), + notFull_(mutex_), + queue_(maxSize) + { + } + + void put(const T& x) + { + MutexLockGuard lock(mutex_); + while (queue_.full()) + { + notFull_.wait(); + } + assert(!queue_.full()); + queue_.push_back(x); + notEmpty_.notify(); + } + + void put(T&& x) + { + MutexLockGuard lock(mutex_); + while (queue_.full()) + { + notFull_.wait(); + } + assert(!queue_.full()); + queue_.push_back(std::move(x)); + notEmpty_.notify(); + } + + T take() + { + MutexLockGuard lock(mutex_); + while (queue_.empty()) + { + notEmpty_.wait(); + } + assert(!queue_.empty()); + T front(std::move(queue_.front())); + queue_.pop_front(); + notFull_.notify(); + return front; + } + + bool empty() const + { + MutexLockGuard lock(mutex_); + return queue_.empty(); + } + + bool full() const + { + MutexLockGuard lock(mutex_); + return queue_.full(); + } + + size_t size() const + { + MutexLockGuard lock(mutex_); + return queue_.size(); + } + + size_t capacity() const + { + MutexLockGuard lock(mutex_); + return queue_.capacity(); + } + + private: + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + Condition notFull_ GUARDED_BY(mutex_); + boost::circular_buffer queue_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H diff --git a/include/muduo/base/CMakeLists.txt b/include/muduo/base/CMakeLists.txt new file mode 100644 index 0000000..96e2d02 --- /dev/null +++ b/include/muduo/base/CMakeLists.txt @@ -0,0 +1,34 @@ +set(base_SRCS + AsyncLogging.cc + Condition.cc + CountDownLatch.cc + CurrentThread.cc + Date.cc + Exception.cc + FileUtil.cc + LogFile.cc + Logging.cc + LogStream.cc + ProcessInfo.cc + Timestamp.cc + Thread.cc + ThreadPool.cc + TimeZone.cc + ) + +add_library(muduo_base ${base_SRCS}) +target_link_libraries(muduo_base pthread rt) + +#add_library(muduo_base_cpp11 ${base_SRCS}) +#target_link_libraries(muduo_base_cpp11 pthread rt) +#set_target_properties(muduo_base_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") + +install(TARGETS muduo_base DESTINATION lib) +#install(TARGETS muduo_base_cpp11 DESTINATION lib) + +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION include/muduo/base) + +if(MUDUO_BUILD_EXAMPLES) + add_subdirectory(tests) +endif() diff --git a/include/muduo/base/Condition.cc b/include/muduo/base/Condition.cc new file mode 100644 index 0000000..47e9d23 --- /dev/null +++ b/include/muduo/base/Condition.cc @@ -0,0 +1,26 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Condition.h" + +#include + +// returns true if time out, false otherwise. +bool muduo::Condition::waitForSeconds(double seconds) +{ + struct timespec abstime; + // FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind. + clock_gettime(CLOCK_REALTIME, &abstime); + + const int64_t kNanoSecondsPerSecond = 1000000000; + int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); + + abstime.tv_sec += static_cast((abstime.tv_nsec + nanoseconds) / kNanoSecondsPerSecond); + abstime.tv_nsec = static_cast((abstime.tv_nsec + nanoseconds) % kNanoSecondsPerSecond); + + MutexLock::UnassignGuard ug(mutex_); + return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime); +} + diff --git a/include/muduo/base/Condition.h b/include/muduo/base/Condition.h new file mode 100644 index 0000000..0181550 --- /dev/null +++ b/include/muduo/base/Condition.h @@ -0,0 +1,56 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_CONDITION_H +#define MUDUO_BASE_CONDITION_H + +#include "muduo/base/Mutex.h" + +#include + +namespace muduo +{ + +class Condition : noncopyable +{ + public: + explicit Condition(MutexLock& mutex) + : mutex_(mutex) + { + MCHECK(pthread_cond_init(&pcond_, NULL)); + } + + ~Condition() + { + MCHECK(pthread_cond_destroy(&pcond_)); + } + + void wait() + { + MutexLock::UnassignGuard ug(mutex_); + MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex())); + } + + // returns true if time out, false otherwise. + bool waitForSeconds(double seconds); + + void notify() + { + MCHECK(pthread_cond_signal(&pcond_)); + } + + void notifyAll() + { + MCHECK(pthread_cond_broadcast(&pcond_)); + } + + private: + MutexLock& mutex_; + pthread_cond_t pcond_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_CONDITION_H diff --git a/include/muduo/base/CountDownLatch.cc b/include/muduo/base/CountDownLatch.cc new file mode 100644 index 0000000..72d26cc --- /dev/null +++ b/include/muduo/base/CountDownLatch.cc @@ -0,0 +1,41 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/CountDownLatch.h" + +using namespace muduo; + +CountDownLatch::CountDownLatch(int count) + : mutex_(), + condition_(mutex_), + count_(count) +{ +} + +void CountDownLatch::wait() +{ + MutexLockGuard lock(mutex_); + while (count_ > 0) + { + condition_.wait(); + } +} + +void CountDownLatch::countDown() +{ + MutexLockGuard lock(mutex_); + --count_; + if (count_ == 0) + { + condition_.notifyAll(); + } +} + +int CountDownLatch::getCount() const +{ + MutexLockGuard lock(mutex_); + return count_; +} + diff --git a/include/muduo/base/CountDownLatch.h b/include/muduo/base/CountDownLatch.h new file mode 100644 index 0000000..9919aef --- /dev/null +++ b/include/muduo/base/CountDownLatch.h @@ -0,0 +1,34 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_COUNTDOWNLATCH_H +#define MUDUO_BASE_COUNTDOWNLATCH_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +namespace muduo +{ + +class CountDownLatch : noncopyable +{ + public: + + explicit CountDownLatch(int count); + + void wait(); + + void countDown(); + + int getCount() const; + + private: + mutable MutexLock mutex_; + Condition condition_ GUARDED_BY(mutex_); + int count_ GUARDED_BY(mutex_); +}; + +} // namespace muduo +#endif // MUDUO_BASE_COUNTDOWNLATCH_H diff --git a/include/muduo/base/CurrentThread.cc b/include/muduo/base/CurrentThread.cc new file mode 100644 index 0000000..15edff0 --- /dev/null +++ b/include/muduo/base/CurrentThread.cc @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +namespace muduo +{ +namespace CurrentThread +{ +__thread int t_cachedTid = 0; +__thread char t_tidString[32]; +__thread int t_tidStringLength = 6; +__thread const char* t_threadName = "unknown"; +static_assert(std::is_same::value, "pid_t should be int"); + +string stackTrace(bool demangle) +{ + string stack; + const int max_frames = 200; + void* frame[max_frames]; + int nptrs = ::backtrace(frame, max_frames); + char** strings = ::backtrace_symbols(frame, nptrs); + if (strings) + { + size_t len = 256; + char* demangled = demangle ? static_cast(::malloc(len)) : nullptr; + for (int i = 1; i < nptrs; ++i) // skipping the 0-th, which is this function + { + if (demangle) + { + // https://panthema.net/2008/0901-stacktrace-demangled/ + // bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909] + char* left_par = nullptr; + char* plus = nullptr; + for (char* p = strings[i]; *p; ++p) + { + if (*p == '(') + left_par = p; + else if (*p == '+') + plus = p; + } + + if (left_par && plus) + { + *plus = '\0'; + int status = 0; + char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status); + *plus = '+'; + if (status == 0) + { + demangled = ret; // ret could be realloc() + stack.append(strings[i], left_par+1); + stack.append(demangled); + stack.append(plus); + stack.push_back('\n'); + continue; + } + } + } + // Fallback to mangled names + stack.append(strings[i]); + stack.push_back('\n'); + } + free(demangled); + free(strings); + } + return stack; +} + +} // namespace CurrentThread +} // namespace muduo diff --git a/include/muduo/base/CurrentThread.h b/include/muduo/base/CurrentThread.h new file mode 100644 index 0000000..33fd8c0 --- /dev/null +++ b/include/muduo/base/CurrentThread.h @@ -0,0 +1,54 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_CURRENTTHREAD_H +#define MUDUO_BASE_CURRENTTHREAD_H + +#include "muduo/base/Types.h" + +namespace muduo +{ +namespace CurrentThread +{ + // internal + extern __thread int t_cachedTid; + extern __thread char t_tidString[32]; + extern __thread int t_tidStringLength; + extern __thread const char* t_threadName; + void cacheTid(); + + inline int tid() + { + if (__builtin_expect(t_cachedTid == 0, 0)) + { + cacheTid(); + } + return t_cachedTid; + } + + inline const char* tidString() // for logging + { + return t_tidString; + } + + inline int tidStringLength() // for logging + { + return t_tidStringLength; + } + + inline const char* name() + { + return t_threadName; + } + + bool isMainThread(); + + void sleepUsec(int64_t usec); // for testing + + string stackTrace(bool demangle); +} // namespace CurrentThread +} // namespace muduo + +#endif // MUDUO_BASE_CURRENTTHREAD_H diff --git a/include/muduo/base/Date.cc b/include/muduo/base/Date.cc new file mode 100644 index 0000000..86b6071 --- /dev/null +++ b/include/muduo/base/Date.cc @@ -0,0 +1,76 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Date.h" +#include // snprintf +#include // struct tm + +namespace muduo +{ +namespace detail +{ + +char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; + +// algorithm and explanation see: +// http://www.faqs.org/faqs/calendars/faq/part2/ +// http://blog.csdn.net/Solstice + +int getJulianDayNumber(int year, int month, int day) +{ + (void) require_32_bit_integer_at_least; // no warning please + int a = (14 - month) / 12; + int y = year + 4800 - a; + int m = month + 12 * a - 3; + return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; +} + +struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) +{ + int a = julianDayNumber + 32044; + int b = (4 * a + 3) / 146097; + int c = a - ((b * 146097) / 4); + int d = (4 * c + 3) / 1461; + int e = c - ((1461 * d) / 4); + int m = (5 * e + 2) / 153; + Date::YearMonthDay ymd; + ymd.day = e - ((153 * m + 2) / 5) + 1; + ymd.month = m + 3 - 12 * (m / 10); + ymd.year = b * 100 + d - 4800 + (m / 10); + return ymd; +} +} // namespace detail +const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1); +} // namespace muduo + +using namespace muduo; +using namespace muduo::detail; + +Date::Date(int y, int m, int d) + : julianDayNumber_(getJulianDayNumber(y, m, d)) +{ +} + +Date::Date(const struct tm& t) + : julianDayNumber_(getJulianDayNumber( + t.tm_year+1900, + t.tm_mon+1, + t.tm_mday)) +{ +} + +string Date::toIsoString() const +{ + char buf[32]; + YearMonthDay ymd(yearMonthDay()); + snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); + return buf; +} + +Date::YearMonthDay Date::yearMonthDay() const +{ + return getYearMonthDay(julianDayNumber_); +} + diff --git a/include/muduo/base/Date.h b/include/muduo/base/Date.h new file mode 100644 index 0000000..2e27b19 --- /dev/null +++ b/include/muduo/base/Date.h @@ -0,0 +1,119 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_DATE_H +#define MUDUO_BASE_DATE_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +struct tm; + +namespace muduo +{ + +/// +/// Date in Gregorian calendar. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// +class Date : public muduo::copyable + // public boost::less_than_comparable, + // public boost::equality_comparable +{ + public: + + struct YearMonthDay + { + int year; // [1900..2500] + int month; // [1..12] + int day; // [1..31] + }; + + static const int kDaysPerWeek = 7; + static const int kJulianDayOf1970_01_01; + + /// + /// Constucts an invalid Date. + /// + Date() + : julianDayNumber_(0) + {} + + /// + /// Constucts a yyyy-mm-dd Date. + /// + /// 1 <= month <= 12 + Date(int year, int month, int day); + + /// + /// Constucts a Date from Julian Day Number. + /// + explicit Date(int julianDayNum) + : julianDayNumber_(julianDayNum) + {} + + /// + /// Constucts a Date from struct tm + /// + explicit Date(const struct tm&); + + // default copy/assignment/dtor are Okay + + void swap(Date& that) + { + std::swap(julianDayNumber_, that.julianDayNumber_); + } + + bool valid() const { return julianDayNumber_ > 0; } + + /// + /// Converts to yyyy-mm-dd format. + /// + string toIsoString() const; + + struct YearMonthDay yearMonthDay() const; + + int year() const + { + return yearMonthDay().year; + } + + int month() const + { + return yearMonthDay().month; + } + + int day() const + { + return yearMonthDay().day; + } + + // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ] + int weekDay() const + { + return (julianDayNumber_+1) % kDaysPerWeek; + } + + int julianDayNumber() const { return julianDayNumber_; } + + private: + int julianDayNumber_; +}; + +inline bool operator<(Date x, Date y) +{ + return x.julianDayNumber() < y.julianDayNumber(); +} + +inline bool operator==(Date x, Date y) +{ + return x.julianDayNumber() == y.julianDayNumber(); +} + +} // namespace muduo + +#endif // MUDUO_BASE_DATE_H diff --git a/include/muduo/base/Exception.cc b/include/muduo/base/Exception.cc new file mode 100644 index 0000000..6e2afbe --- /dev/null +++ b/include/muduo/base/Exception.cc @@ -0,0 +1,18 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Exception.h" +#include "muduo/base/CurrentThread.h" + +namespace muduo +{ + +Exception::Exception(string msg) + : message_(std::move(msg)), + stack_(CurrentThread::stackTrace(/*demangle=*/false)) +{ +} + +} // namespace muduo diff --git a/include/muduo/base/Exception.h b/include/muduo/base/Exception.h new file mode 100644 index 0000000..2a74622 --- /dev/null +++ b/include/muduo/base/Exception.h @@ -0,0 +1,40 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_EXCEPTION_H +#define MUDUO_BASE_EXCEPTION_H + +#include "muduo/base/Types.h" +#include + +namespace muduo +{ + +class Exception : public std::exception +{ + public: + Exception(string what); + ~Exception() noexcept override = default; + + // default copy-ctor and operator= are okay. + + const char* what() const noexcept override + { + return message_.c_str(); + } + + const char* stackTrace() const noexcept + { + return stack_.c_str(); + } + + private: + string message_; + string stack_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_EXCEPTION_H diff --git a/include/muduo/base/FileUtil.cc b/include/muduo/base/FileUtil.cc new file mode 100644 index 0000000..2a73886 --- /dev/null +++ b/include/muduo/base/FileUtil.cc @@ -0,0 +1,181 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/FileUtil.h" +#include "muduo/base/Logging.h" + +#include +#include +#include +#include +#include +#include + +using namespace muduo; + +FileUtil::AppendFile::AppendFile(StringArg filename) + : fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC + writtenBytes_(0) +{ + assert(fp_); + ::setbuffer(fp_, buffer_, sizeof buffer_); + // posix_fadvise POSIX_FADV_DONTNEED ? +} + +FileUtil::AppendFile::~AppendFile() +{ + ::fclose(fp_); +} + +void FileUtil::AppendFile::append(const char* logline, const size_t len) +{ + size_t n = write(logline, len); + size_t remain = len - n; + while (remain > 0) + { + size_t x = write(logline + n, remain); + if (x == 0) + { + int err = ferror(fp_); + if (err) + { + fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err)); + } + break; + } + n += x; + remain = len - n; // remain -= x + } + + writtenBytes_ += len; +} + +void FileUtil::AppendFile::flush() +{ + ::fflush(fp_); +} + +size_t FileUtil::AppendFile::write(const char* logline, size_t len) +{ + // #undef fwrite_unlocked + return ::fwrite_unlocked(logline, 1, len, fp_); +} + +FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename) + : fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), + err_(0) +{ + buf_[0] = '\0'; + if (fd_ < 0) + { + err_ = errno; + } +} + +FileUtil::ReadSmallFile::~ReadSmallFile() +{ + if (fd_ >= 0) + { + ::close(fd_); // FIXME: check EINTR + } +} + +// return errno +template +int FileUtil::ReadSmallFile::readToString(int maxSize, + String* content, + int64_t* fileSize, + int64_t* modifyTime, + int64_t* createTime) +{ + static_assert(sizeof(off_t) == 8, "_FILE_OFFSET_BITS = 64"); + assert(content != NULL); + int err = err_; + if (fd_ >= 0) + { + content->clear(); + + if (fileSize) + { + struct stat statbuf; + if (::fstat(fd_, &statbuf) == 0) + { + if (S_ISREG(statbuf.st_mode)) + { + *fileSize = statbuf.st_size; + content->reserve(static_cast(std::min(implicit_cast(maxSize), *fileSize))); + } + else if (S_ISDIR(statbuf.st_mode)) + { + err = EISDIR; + } + if (modifyTime) + { + *modifyTime = statbuf.st_mtime; + } + if (createTime) + { + *createTime = statbuf.st_ctime; + } + } + else + { + err = errno; + } + } + + while (content->size() < implicit_cast(maxSize)) + { + size_t toRead = std::min(implicit_cast(maxSize) - content->size(), sizeof(buf_)); + ssize_t n = ::read(fd_, buf_, toRead); + if (n > 0) + { + content->append(buf_, n); + } + else + { + if (n < 0) + { + err = errno; + } + break; + } + } + } + return err; +} + +int FileUtil::ReadSmallFile::readToBuffer(int* size) +{ + int err = err_; + if (fd_ >= 0) + { + ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0); + if (n >= 0) + { + if (size) + { + *size = static_cast(n); + } + buf_[n] = '\0'; + } + else + { + err = errno; + } + } + return err; +} + +template int FileUtil::readFile(StringArg filename, + int maxSize, + string* content, + int64_t*, int64_t*, int64_t*); + +template int FileUtil::ReadSmallFile::readToString( + int maxSize, + string* content, + int64_t*, int64_t*, int64_t*); + diff --git a/include/muduo/base/FileUtil.h b/include/muduo/base/FileUtil.h new file mode 100644 index 0000000..62ddebc --- /dev/null +++ b/include/muduo/base/FileUtil.h @@ -0,0 +1,89 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_BASE_FILEUTIL_H +#define MUDUO_BASE_FILEUTIL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include // for off_t + +namespace muduo +{ +namespace FileUtil +{ + +// read small file < 64KB +class ReadSmallFile : noncopyable +{ + public: + ReadSmallFile(StringArg filename); + ~ReadSmallFile(); + + // return errno + template + int readToString(int maxSize, + String* content, + int64_t* fileSize, + int64_t* modifyTime, + int64_t* createTime); + + /// Read at maxium kBufferSize into buf_ + // return errno + int readToBuffer(int* size); + + const char* buffer() const { return buf_; } + + static const int kBufferSize = 64*1024; + + private: + int fd_; + int err_; + char buf_[kBufferSize]; +}; + +// read the file content, returns errno if error happens. +template +int readFile(StringArg filename, + int maxSize, + String* content, + int64_t* fileSize = NULL, + int64_t* modifyTime = NULL, + int64_t* createTime = NULL) +{ + ReadSmallFile file(filename); + return file.readToString(maxSize, content, fileSize, modifyTime, createTime); +} + +// not thread safe +class AppendFile : noncopyable +{ + public: + explicit AppendFile(StringArg filename); + + ~AppendFile(); + + void append(const char* logline, size_t len); + + void flush(); + + off_t writtenBytes() const { return writtenBytes_; } + + private: + + size_t write(const char* logline, size_t len); + + FILE* fp_; + char buffer_[64*1024]; + off_t writtenBytes_; +}; + +} // namespace FileUtil +} // namespace muduo + +#endif // MUDUO_BASE_FILEUTIL_H + diff --git a/include/muduo/base/GzipFile.h b/include/muduo/base/GzipFile.h new file mode 100644 index 0000000..68a538c --- /dev/null +++ b/include/muduo/base/GzipFile.h @@ -0,0 +1,89 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#pragma once + +#include "muduo/base/StringPiece.h" +#include "muduo/base/noncopyable.h" +#include + +namespace muduo +{ + +class GzipFile : noncopyable +{ + public: + GzipFile(GzipFile&& rhs) noexcept + : file_(rhs.file_) + { + rhs.file_ = NULL; + } + + ~GzipFile() + { + if (file_) + { + ::gzclose(file_); + } + } + + GzipFile& operator=(GzipFile&& rhs) noexcept + { + swap(rhs); + return *this; + } + + bool valid() const { return file_ != NULL; } + void swap(GzipFile& rhs) { std::swap(file_, rhs.file_); } +#if ZLIB_VERNUM >= 0x1240 + bool setBuffer(int size) { return ::gzbuffer(file_, size) == 0; } +#endif + + // return the number of uncompressed bytes actually read, 0 for eof, -1 for error + int read(void* buf, int len) { return ::gzread(file_, buf, len); } + + // return the number of uncompressed bytes actually written + int write(StringPiece buf) { return ::gzwrite(file_, buf.data(), buf.size()); } + + // number of uncompressed bytes + off_t tell() const { return ::gztell(file_); } + +#if ZLIB_VERNUM >= 0x1240 + // number of compressed bytes + off_t offset() const { return ::gzoffset(file_); } +#endif + + // int flush(int f) { return ::gzflush(file_, f); } + + static GzipFile openForRead(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "rbe")); + } + + static GzipFile openForAppend(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "abe")); + } + + static GzipFile openForWriteExclusive(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "wbxe")); + } + + static GzipFile openForWriteTruncate(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "wbe")); + } + + private: + explicit GzipFile(gzFile file) + : file_(file) + { + } + + gzFile file_; +}; + +} // namespace muduo diff --git a/include/muduo/base/LogFile.cc b/include/muduo/base/LogFile.cc new file mode 100644 index 0000000..2a12abe --- /dev/null +++ b/include/muduo/base/LogFile.cc @@ -0,0 +1,133 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/LogFile.h" + +#include "muduo/base/FileUtil.h" +#include "muduo/base/ProcessInfo.h" + +#include +#include +#include + +using namespace muduo; + +LogFile::LogFile(const string& basename, + off_t rollSize, + bool threadSafe, + int flushInterval, + int checkEveryN) + : basename_(basename), + rollSize_(rollSize), + flushInterval_(flushInterval), + checkEveryN_(checkEveryN), + count_(0), + mutex_(threadSafe ? new MutexLock : NULL), + startOfPeriod_(0), + lastRoll_(0), + lastFlush_(0) +{ + assert(basename.find('/') == string::npos); + rollFile(); +} + +LogFile::~LogFile() = default; + +void LogFile::append(const char* logline, int len) +{ + if (mutex_) + { + MutexLockGuard lock(*mutex_); + append_unlocked(logline, len); + } + else + { + append_unlocked(logline, len); + } +} + +void LogFile::flush() +{ + if (mutex_) + { + MutexLockGuard lock(*mutex_); + file_->flush(); + } + else + { + file_->flush(); + } +} + +void LogFile::append_unlocked(const char* logline, int len) +{ + file_->append(logline, len); + + if (file_->writtenBytes() > rollSize_) + { + rollFile(); + } + else + { + ++count_; + if (count_ >= checkEveryN_) + { + count_ = 0; + time_t now = ::time(NULL); + time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_; + if (thisPeriod_ != startOfPeriod_) + { + rollFile(); + } + else if (now - lastFlush_ > flushInterval_) + { + lastFlush_ = now; + file_->flush(); + } + } + } +} + +bool LogFile::rollFile() +{ + time_t now = 0; + string filename = getLogFileName(basename_, &now); + time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; + + if (now > lastRoll_) + { + lastRoll_ = now; + lastFlush_ = now; + startOfPeriod_ = start; + file_.reset(new FileUtil::AppendFile(filename)); + return true; + } + return false; +} + +string LogFile::getLogFileName(const string& basename, time_t* now) +{ + string filename; + filename.reserve(basename.size() + 64); + filename = basename; + + char timebuf[32]; + struct tm tm; + *now = time(NULL); + gmtime_r(now, &tm); // FIXME: localtime_r ? + strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm); + filename += timebuf; + + filename += ProcessInfo::hostname(); + + char pidbuf[32]; + snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); + filename += pidbuf; + + filename += ".log"; + + return filename; +} + diff --git a/include/muduo/base/LogFile.h b/include/muduo/base/LogFile.h new file mode 100644 index 0000000..7abd583 --- /dev/null +++ b/include/muduo/base/LogFile.h @@ -0,0 +1,58 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGFILE_H +#define MUDUO_BASE_LOGFILE_H + +#include "muduo/base/Mutex.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ + +namespace FileUtil +{ +class AppendFile; +} + +class LogFile : noncopyable +{ + public: + LogFile(const string& basename, + off_t rollSize, + bool threadSafe = true, + int flushInterval = 3, + int checkEveryN = 1024); + ~LogFile(); + + void append(const char* logline, int len); + void flush(); + bool rollFile(); + + private: + void append_unlocked(const char* logline, int len); + + static string getLogFileName(const string& basename, time_t* now); + + const string basename_; + const off_t rollSize_; + const int flushInterval_; + const int checkEveryN_; + + int count_; + + std::unique_ptr mutex_; + time_t startOfPeriod_; + time_t lastRoll_; + time_t lastFlush_; + std::unique_ptr file_; + + const static int kRollPerSeconds_ = 60*60*24; +}; + +} // namespace muduo +#endif // MUDUO_BASE_LOGFILE_H diff --git a/include/muduo/base/LogStream.cc b/include/muduo/base/LogStream.cc new file mode 100644 index 0000000..cafd5b8 --- /dev/null +++ b/include/muduo/base/LogStream.cc @@ -0,0 +1,342 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/LogStream.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include + + +using namespace muduo; +using namespace muduo::detail; + +// TODO: better itoa. +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wtautological-compare" +#else +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +namespace muduo +{ +namespace detail +{ + +const char digits[] = "9876543210123456789"; +const char* zero = digits + 9; +static_assert(sizeof(digits) == 20, "wrong number of digits"); + +const char digitsHex[] = "0123456789ABCDEF"; +static_assert(sizeof digitsHex == 17, "wrong number of digitsHex"); + +// Efficient Integer to String Conversions, by Matthew Wilson. +template +size_t convert(char buf[], T value) +{ + T i = value; + char* p = buf; + + do + { + int lsd = static_cast(i % 10); + i /= 10; + *p++ = zero[lsd]; + } while (i != 0); + + if (value < 0) + { + *p++ = '-'; + } + *p = '\0'; + std::reverse(buf, p); + + return p - buf; +} + +size_t convertHex(char buf[], uintptr_t value) +{ + uintptr_t i = value; + char* p = buf; + + do + { + int lsd = static_cast(i % 16); + i /= 16; + *p++ = digitsHex[lsd]; + } while (i != 0); + + *p = '\0'; + std::reverse(buf, p); + + return p - buf; +} + +template class FixedBuffer; +template class FixedBuffer; + +} // namespace detail + +/* + Format a number with 5 characters, including SI units. + [0, 999] + [1.00k, 999k] + [1.00M, 999M] + [1.00G, 999G] + [1.00T, 999T] + [1.00P, 999P] + [1.00E, inf) +*/ +std::string formatSI(int64_t s) +{ + double n = static_cast(s); + char buf[64]; + if (s < 1000) + snprintf(buf, sizeof(buf), "%" PRId64, s); + else if (s < 9995) + snprintf(buf, sizeof(buf), "%.2fk", n/1e3); + else if (s < 99950) + snprintf(buf, sizeof(buf), "%.1fk", n/1e3); + else if (s < 999500) + snprintf(buf, sizeof(buf), "%.0fk", n/1e3); + else if (s < 9995000) + snprintf(buf, sizeof(buf), "%.2fM", n/1e6); + else if (s < 99950000) + snprintf(buf, sizeof(buf), "%.1fM", n/1e6); + else if (s < 999500000) + snprintf(buf, sizeof(buf), "%.0fM", n/1e6); + else if (s < 9995000000) + snprintf(buf, sizeof(buf), "%.2fG", n/1e9); + else if (s < 99950000000) + snprintf(buf, sizeof(buf), "%.1fG", n/1e9); + else if (s < 999500000000) + snprintf(buf, sizeof(buf), "%.0fG", n/1e9); + else if (s < 9995000000000) + snprintf(buf, sizeof(buf), "%.2fT", n/1e12); + else if (s < 99950000000000) + snprintf(buf, sizeof(buf), "%.1fT", n/1e12); + else if (s < 999500000000000) + snprintf(buf, sizeof(buf), "%.0fT", n/1e12); + else if (s < 9995000000000000) + snprintf(buf, sizeof(buf), "%.2fP", n/1e15); + else if (s < 99950000000000000) + snprintf(buf, sizeof(buf), "%.1fP", n/1e15); + else if (s < 999500000000000000) + snprintf(buf, sizeof(buf), "%.0fP", n/1e15); + else + snprintf(buf, sizeof(buf), "%.2fE", n/1e18); + return buf; +} + +/* + [0, 1023] + [1.00Ki, 9.99Ki] + [10.0Ki, 99.9Ki] + [ 100Ki, 1023Ki] + [1.00Mi, 9.99Mi] +*/ +std::string formatIEC(int64_t s) +{ + double n = static_cast(s); + char buf[64]; + const double Ki = 1024.0; + const double Mi = Ki * 1024.0; + const double Gi = Mi * 1024.0; + const double Ti = Gi * 1024.0; + const double Pi = Ti * 1024.0; + const double Ei = Pi * 1024.0; + + if (n < Ki) + snprintf(buf, sizeof buf, "%" PRId64, s); + else if (n < Ki*9.995) + snprintf(buf, sizeof buf, "%.2fKi", n / Ki); + else if (n < Ki*99.95) + snprintf(buf, sizeof buf, "%.1fKi", n / Ki); + else if (n < Ki*1023.5) + snprintf(buf, sizeof buf, "%.0fKi", n / Ki); + + else if (n < Mi*9.995) + snprintf(buf, sizeof buf, "%.2fMi", n / Mi); + else if (n < Mi*99.95) + snprintf(buf, sizeof buf, "%.1fMi", n / Mi); + else if (n < Mi*1023.5) + snprintf(buf, sizeof buf, "%.0fMi", n / Mi); + + else if (n < Gi*9.995) + snprintf(buf, sizeof buf, "%.2fGi", n / Gi); + else if (n < Gi*99.95) + snprintf(buf, sizeof buf, "%.1fGi", n / Gi); + else if (n < Gi*1023.5) + snprintf(buf, sizeof buf, "%.0fGi", n / Gi); + + else if (n < Ti*9.995) + snprintf(buf, sizeof buf, "%.2fTi", n / Ti); + else if (n < Ti*99.95) + snprintf(buf, sizeof buf, "%.1fTi", n / Ti); + else if (n < Ti*1023.5) + snprintf(buf, sizeof buf, "%.0fTi", n / Ti); + + else if (n < Pi*9.995) + snprintf(buf, sizeof buf, "%.2fPi", n / Pi); + else if (n < Pi*99.95) + snprintf(buf, sizeof buf, "%.1fPi", n / Pi); + else if (n < Pi*1023.5) + snprintf(buf, sizeof buf, "%.0fPi", n / Pi); + + else if (n < Ei*9.995) + snprintf(buf, sizeof buf, "%.2fEi", n / Ei ); + else + snprintf(buf, sizeof buf, "%.1fEi", n / Ei ); + return buf; +} + +} // namespace muduo + +template +const char* FixedBuffer::debugString() +{ + *cur_ = '\0'; + return data_; +} + +template +void FixedBuffer::cookieStart() +{ +} + +template +void FixedBuffer::cookieEnd() +{ +} + +void LogStream::staticCheck() +{ + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); +} + +template +void LogStream::formatInteger(T v) +{ + if (buffer_.avail() >= kMaxNumericSize) + { + size_t len = convert(buffer_.current(), v); + buffer_.add(len); + } +} + +LogStream& LogStream::operator<<(short v) +{ + *this << static_cast(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned short v) +{ + *this << static_cast(v); + return *this; +} + +LogStream& LogStream::operator<<(int v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned int v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(long long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned long long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(const void* p) +{ + uintptr_t v = reinterpret_cast(p); + if (buffer_.avail() >= kMaxNumericSize) + { + char* buf = buffer_.current(); + buf[0] = '0'; + buf[1] = 'x'; + size_t len = convertHex(buf+2, v); + buffer_.add(len+2); + } + return *this; +} + +// FIXME: replace this with Grisu3 by Florian Loitsch. +LogStream& LogStream::operator<<(double v) +{ + if (buffer_.avail() >= kMaxNumericSize) + { + int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v); + buffer_.add(len); + } + return *this; +} + +template +Fmt::Fmt(const char* fmt, T val) +{ + static_assert(std::is_arithmetic::value == true, "Must be arithmetic type"); + + length_ = snprintf(buf_, sizeof buf_, fmt, val); + assert(static_cast(length_) < sizeof buf_); +} + +// Explicit instantiations + +template Fmt::Fmt(const char* fmt, char); + +template Fmt::Fmt(const char* fmt, short); +template Fmt::Fmt(const char* fmt, unsigned short); +template Fmt::Fmt(const char* fmt, int); +template Fmt::Fmt(const char* fmt, unsigned int); +template Fmt::Fmt(const char* fmt, long); +template Fmt::Fmt(const char* fmt, unsigned long); +template Fmt::Fmt(const char* fmt, long long); +template Fmt::Fmt(const char* fmt, unsigned long long); + +template Fmt::Fmt(const char* fmt, float); +template Fmt::Fmt(const char* fmt, double); diff --git a/include/muduo/base/LogStream.h b/include/muduo/base/LogStream.h new file mode 100644 index 0000000..a28eb46 --- /dev/null +++ b/include/muduo/base/LogStream.h @@ -0,0 +1,203 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGSTREAM_H +#define MUDUO_BASE_LOGSTREAM_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include +#include // memcpy + +namespace muduo +{ + +namespace detail +{ + +const int kSmallBuffer = 4000; +const int kLargeBuffer = 4000*1000; + +template +class FixedBuffer : noncopyable +{ + public: + FixedBuffer() + : cur_(data_) + { + setCookie(cookieStart); + } + + ~FixedBuffer() + { + setCookie(cookieEnd); + } + + void append(const char* /*restrict*/ buf, size_t len) + { + // FIXME: append partially + if (implicit_cast(avail()) > len) + { + memcpy(cur_, buf, len); + cur_ += len; + } + } + + const char* data() const { return data_; } + int length() const { return static_cast(cur_ - data_); } + + // write to data_ directly + char* current() { return cur_; } + int avail() const { return static_cast(end() - cur_); } + void add(size_t len) { cur_ += len; } + + void reset() { cur_ = data_; } + void bzero() { memZero(data_, sizeof data_); } + + // for used by GDB + const char* debugString(); + void setCookie(void (*cookie)()) { cookie_ = cookie; } + // for used by unit test + string toString() const { return string(data_, length()); } + StringPiece toStringPiece() const { return StringPiece(data_, length()); } + + private: + const char* end() const { return data_ + sizeof data_; } + // Must be outline function for cookies. + static void cookieStart(); + static void cookieEnd(); + + void (*cookie_)(); + char data_[SIZE]; + char* cur_; +}; + +} // namespace detail + +class LogStream : noncopyable +{ + typedef LogStream self; + public: + typedef detail::FixedBuffer Buffer; + + self& operator<<(bool v) + { + buffer_.append(v ? "1" : "0", 1); + return *this; + } + + self& operator<<(short); + self& operator<<(unsigned short); + self& operator<<(int); + self& operator<<(unsigned int); + self& operator<<(long); + self& operator<<(unsigned long); + self& operator<<(long long); + self& operator<<(unsigned long long); + + self& operator<<(const void*); + + self& operator<<(float v) + { + *this << static_cast(v); + return *this; + } + self& operator<<(double); + // self& operator<<(long double); + + self& operator<<(char v) + { + buffer_.append(&v, 1); + return *this; + } + + // self& operator<<(signed char); + // self& operator<<(unsigned char); + + self& operator<<(const char* str) + { + if (str) + { + buffer_.append(str, strlen(str)); + } + else + { + buffer_.append("(null)", 6); + } + return *this; + } + + self& operator<<(const unsigned char* str) + { + return operator<<(reinterpret_cast(str)); + } + + self& operator<<(const string& v) + { + buffer_.append(v.c_str(), v.size()); + return *this; + } + + self& operator<<(const StringPiece& v) + { + buffer_.append(v.data(), v.size()); + return *this; + } + + self& operator<<(const Buffer& v) + { + *this << v.toStringPiece(); + return *this; + } + + void append(const char* data, int len) { buffer_.append(data, len); } + const Buffer& buffer() const { return buffer_; } + void resetBuffer() { buffer_.reset(); } + + private: + void staticCheck(); + + template + void formatInteger(T); + + Buffer buffer_; + + static const int kMaxNumericSize = 32; +}; + +class Fmt // : noncopyable +{ + public: + template + Fmt(const char* fmt, T val); + + const char* data() const { return buf_; } + int length() const { return length_; } + + private: + char buf_[32]; + int length_; +}; + +inline LogStream& operator<<(LogStream& s, const Fmt& fmt) +{ + s.append(fmt.data(), fmt.length()); + return s; +} + +// Format quantity n in SI units (k, M, G, T, P, E). +// The returned string is atmost 5 characters long. +// Requires n >= 0 +string formatSI(int64_t n); + +// Format quantity n in IEC (binary) units (Ki, Mi, Gi, Ti, Pi, Ei). +// The returned string is atmost 6 characters long. +// Requires n >= 0 +string formatIEC(int64_t n); + +} // namespace muduo + +#endif // MUDUO_BASE_LOGSTREAM_H diff --git a/include/muduo/base/Logging.cc b/include/muduo/base/Logging.cc new file mode 100644 index 0000000..c09a8ce --- /dev/null +++ b/include/muduo/base/Logging.cc @@ -0,0 +1,227 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Logging.h" + +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Timestamp.h" +#include "muduo/base/TimeZone.h" + +#include +#include +#include + +#include + +namespace muduo +{ + +/* +class LoggerImpl +{ + public: + typedef Logger::LogLevel LogLevel; + LoggerImpl(LogLevel level, int old_errno, const char* file, int line); + void finish(); + + Timestamp time_; + LogStream stream_; + LogLevel level_; + int line_; + const char* fullname_; + const char* basename_; +}; +*/ + +__thread char t_errnobuf[512]; +__thread char t_time[64]; +__thread time_t t_lastSecond; + +const char* strerror_tl(int savedErrno) +{ + return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); +} + +Logger::LogLevel initLogLevel() +{ + if (::getenv("MUDUO_LOG_TRACE")) + return Logger::TRACE; + else if (::getenv("MUDUO_LOG_DEBUG")) + return Logger::DEBUG; + else + return Logger::INFO; +} + +Logger::LogLevel g_logLevel = initLogLevel(); + +const char* LogLevelName[Logger::NUM_LOG_LEVELS] = +{ + "TRACE ", + "DEBUG ", + "INFO ", + "WARN ", + "ERROR ", + "FATAL ", +}; + +// helper class for known string length at compile time +class T +{ + public: + T(const char* str, unsigned len) + :str_(str), + len_(len) + { + assert(strlen(str) == len_); + } + + const char* str_; + const unsigned len_; +}; + +inline LogStream& operator<<(LogStream& s, T v) +{ + s.append(v.str_, v.len_); + return s; +} + +inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v) +{ + s.append(v.data_, v.size_); + return s; +} + +void defaultOutput(const char* msg, int len) +{ + size_t n = fwrite(msg, 1, len, stdout); + //FIXME check n + (void)n; +} + +void defaultFlush() +{ + fflush(stdout); +} + +Logger::OutputFunc g_output = defaultOutput; +Logger::FlushFunc g_flush = defaultFlush; +TimeZone g_logTimeZone; + +} // namespace muduo + +using namespace muduo; + +Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line) + : time_(Timestamp::now()), + stream_(), + level_(level), + line_(line), + basename_(file) +{ + formatTime(); + CurrentThread::tid(); + stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength()); + stream_ << T(LogLevelName[level], 6); + if (savedErrno != 0) + { + stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; + } +} + +void Logger::Impl::formatTime() +{ + int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch(); + time_t seconds = static_cast(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond); + int microseconds = static_cast(microSecondsSinceEpoch % Timestamp::kMicroSecondsPerSecond); + if (seconds != t_lastSecond) + { + t_lastSecond = seconds; + struct tm tm_time; + if (g_logTimeZone.valid()) + { + tm_time = g_logTimeZone.toLocalTime(seconds); + } + else + { + ::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime + } + + int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + assert(len == 17); (void)len; + } + + if (g_logTimeZone.valid()) + { + Fmt us(".%06d ", microseconds); + assert(us.length() == 8); + stream_ << T(t_time, 17) << T(us.data(), 8); + } + else + { + Fmt us(".%06dZ ", microseconds); + assert(us.length() == 9); + stream_ << T(t_time, 17) << T(us.data(), 9); + } +} + +void Logger::Impl::finish() +{ + stream_ << " - " << basename_ << ':' << line_ << '\n'; +} + +Logger::Logger(SourceFile file, int line) + : impl_(INFO, 0, file, line) +{ +} + +Logger::Logger(SourceFile file, int line, LogLevel level, const char* func) + : impl_(level, 0, file, line) +{ + impl_.stream_ << func << ' '; +} + +Logger::Logger(SourceFile file, int line, LogLevel level) + : impl_(level, 0, file, line) +{ +} + +Logger::Logger(SourceFile file, int line, bool toAbort) + : impl_(toAbort?FATAL:ERROR, errno, file, line) +{ +} + +Logger::~Logger() +{ + impl_.finish(); + const LogStream::Buffer& buf(stream().buffer()); + g_output(buf.data(), buf.length()); + if (impl_.level_ == FATAL) + { + g_flush(); + abort(); + } +} + +void Logger::setLogLevel(Logger::LogLevel level) +{ + g_logLevel = level; +} + +void Logger::setOutput(OutputFunc out) +{ + g_output = out; +} + +void Logger::setFlush(FlushFunc flush) +{ + g_flush = flush; +} + +void Logger::setTimeZone(const TimeZone& tz) +{ + g_logTimeZone = tz; +} diff --git a/include/muduo/base/Logging.h b/include/muduo/base/Logging.h new file mode 100644 index 0000000..be56689 --- /dev/null +++ b/include/muduo/base/Logging.h @@ -0,0 +1,159 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGGING_H +#define MUDUO_BASE_LOGGING_H + +#include "muduo/base/LogStream.h" +#include "muduo/base/Timestamp.h" + +namespace muduo +{ + +class TimeZone; + +class Logger +{ + public: + enum LogLevel + { + TRACE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL, + NUM_LOG_LEVELS, + }; + + // compile time calculation of basename of source file + class SourceFile + { + public: + template + SourceFile(const char (&arr)[N]) + : data_(arr), + size_(N-1) + { + const char* slash = strrchr(data_, '/'); // builtin function + if (slash) + { + data_ = slash + 1; + size_ -= static_cast(data_ - arr); + } + } + + explicit SourceFile(const char* filename) + : data_(filename) + { + const char* slash = strrchr(filename, '/'); + if (slash) + { + data_ = slash + 1; + } + size_ = static_cast(strlen(data_)); + } + + const char* data_; + int size_; + }; + + Logger(SourceFile file, int line); + Logger(SourceFile file, int line, LogLevel level); + Logger(SourceFile file, int line, LogLevel level, const char* func); + Logger(SourceFile file, int line, bool toAbort); + ~Logger(); + + LogStream& stream() { return impl_.stream_; } + + static LogLevel logLevel(); + static void setLogLevel(LogLevel level); + + typedef void (*OutputFunc)(const char* msg, int len); + typedef void (*FlushFunc)(); + static void setOutput(OutputFunc); + static void setFlush(FlushFunc); + static void setTimeZone(const TimeZone& tz); + + private: + +class Impl +{ + public: + typedef Logger::LogLevel LogLevel; + Impl(LogLevel level, int old_errno, const SourceFile& file, int line); + void formatTime(); + void finish(); + + Timestamp time_; + LogStream stream_; + LogLevel level_; + int line_; + SourceFile basename_; +}; + + Impl impl_; + +}; + +extern Logger::LogLevel g_logLevel; + +inline Logger::LogLevel Logger::logLevel() +{ + return g_logLevel; +} + +// +// CAUTION: do not write: +// +// if (good) +// LOG_INFO << "Good news"; +// else +// LOG_WARN << "Bad news"; +// +// this expends to +// +// if (good) +// if (logging_INFO) +// logInfoStream << "Good news"; +// else +// logWarnStream << "Bad news"; +// +#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \ + muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream() +#define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \ + muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream() +#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \ + muduo::Logger(__FILE__, __LINE__).stream() +#define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream() +#define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream() +#define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream() +#define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream() +#define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream() + +const char* strerror_tl(int savedErrno); + +// Taken from glog/logging.h +// +// Check that the input is non NULL. This very useful in constructor +// initializer lists. + +#define CHECK_NOTNULL(val) \ + ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// A small helper for CHECK_NOTNULL(). +template +T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) +{ + if (ptr == NULL) + { + Logger(file, line, Logger::FATAL).stream() << names; + } + return ptr; +} + +} // namespace muduo + +#endif // MUDUO_BASE_LOGGING_H diff --git a/include/muduo/base/Mutex.h b/include/muduo/base/Mutex.h new file mode 100644 index 0000000..20746bd --- /dev/null +++ b/include/muduo/base/Mutex.h @@ -0,0 +1,233 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_MUTEX_H +#define MUDUO_BASE_MUTEX_H + +#include "muduo/base/CurrentThread.h" +#include "muduo/base/noncopyable.h" +#include +#include + +// Thread safety annotations { +// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +// Enable thread safety attributes only with clang. +// The attributes can be safely erased when compiling with other compilers. +#if defined(__clang__) && (!defined(SWIG)) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define SCOPED_CAPABILITY \ + THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define PT_GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define REQUIRES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define REQUIRES_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define RELEASE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define RELEASE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define EXCLUDES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define ASSERT_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define ASSERT_SHARED_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define RETURN_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +// End of thread safety annotations } + +#ifdef CHECK_PTHREAD_RETURN_VALUE + +#ifdef NDEBUG +__BEGIN_DECLS +extern void __assert_perror_fail (int errnum, + const char *file, + unsigned int line, + const char *function) + noexcept __attribute__ ((__noreturn__)); +__END_DECLS +#endif + +#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ + if (__builtin_expect(errnum != 0, 0)) \ + __assert_perror_fail (errnum, __FILE__, __LINE__, __func__);}) + +#else // CHECK_PTHREAD_RETURN_VALUE + +#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ + assert(errnum == 0); (void) errnum;}) + +#endif // CHECK_PTHREAD_RETURN_VALUE + +namespace muduo +{ + +// Use as data member of a class, eg. +// +// class Foo +// { +// public: +// int size() const; +// +// private: +// mutable MutexLock mutex_; +// std::vector data_ GUARDED_BY(mutex_); +// }; +class CAPABILITY("mutex") MutexLock : noncopyable +{ + public: + MutexLock() + : holder_(0) + { + MCHECK(pthread_mutex_init(&mutex_, NULL)); + } + + ~MutexLock() + { + assert(holder_ == 0); + MCHECK(pthread_mutex_destroy(&mutex_)); + } + + // must be called when locked, i.e. for assertion + bool isLockedByThisThread() const + { + return holder_ == CurrentThread::tid(); + } + + void assertLocked() const ASSERT_CAPABILITY(this) + { + assert(isLockedByThisThread()); + } + + // internal usage + + void lock() ACQUIRE() + { + MCHECK(pthread_mutex_lock(&mutex_)); + assignHolder(); + } + + void unlock() RELEASE() + { + unassignHolder(); + MCHECK(pthread_mutex_unlock(&mutex_)); + } + + pthread_mutex_t* getPthreadMutex() /* non-const */ + { + return &mutex_; + } + + private: + friend class Condition; + + class UnassignGuard : noncopyable + { + public: + explicit UnassignGuard(MutexLock& owner) + : owner_(owner) + { + owner_.unassignHolder(); + } + + ~UnassignGuard() + { + owner_.assignHolder(); + } + + private: + MutexLock& owner_; + }; + + void unassignHolder() + { + holder_ = 0; + } + + void assignHolder() + { + holder_ = CurrentThread::tid(); + } + + pthread_mutex_t mutex_; + pid_t holder_; +}; + +// Use as a stack variable, eg. +// int Foo::size() const +// { +// MutexLockGuard lock(mutex_); +// return data_.size(); +// } +class SCOPED_CAPABILITY MutexLockGuard : noncopyable +{ + public: + explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex) + : mutex_(mutex) + { + mutex_.lock(); + } + + ~MutexLockGuard() RELEASE() + { + mutex_.unlock(); + } + + private: + + MutexLock& mutex_; +}; + +} // namespace muduo + +// Prevent misuse like: +// MutexLockGuard(mutex_); +// A tempory object doesn't hold the lock for long! +#define MutexLockGuard(x) error "Missing guard object name" + +#endif // MUDUO_BASE_MUTEX_H diff --git a/include/muduo/base/ProcessInfo.cc b/include/muduo/base/ProcessInfo.cc new file mode 100644 index 0000000..6ab5ad1 --- /dev/null +++ b/include/muduo/base/ProcessInfo.cc @@ -0,0 +1,246 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/ProcessInfo.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/FileUtil.h" + +#include + +#include +#include +#include +#include // snprintf +#include +#include +#include +#include + +namespace muduo +{ +namespace detail +{ +__thread int t_numOpenedFiles = 0; +int fdDirFilter(const struct dirent* d) +{ + if (::isdigit(d->d_name[0])) + { + ++t_numOpenedFiles; + } + return 0; +} + +__thread std::vector* t_pids = NULL; +int taskDirFilter(const struct dirent* d) +{ + if (::isdigit(d->d_name[0])) + { + t_pids->push_back(atoi(d->d_name)); + } + return 0; +} + +int scanDir(const char *dirpath, int (*filter)(const struct dirent *)) +{ + struct dirent** namelist = NULL; + int result = ::scandir(dirpath, &namelist, filter, alphasort); + assert(namelist == NULL); + return result; +} + +Timestamp g_startTime = Timestamp::now(); +// assume those won't change during the life time of a process. +int g_clockTicks = static_cast(::sysconf(_SC_CLK_TCK)); +int g_pageSize = static_cast(::sysconf(_SC_PAGE_SIZE)); +} // namespace detail +} // namespace muduo + +using namespace muduo; +using namespace muduo::detail; + +pid_t ProcessInfo::pid() +{ + return ::getpid(); +} + +string ProcessInfo::pidString() +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", pid()); + return buf; +} + +uid_t ProcessInfo::uid() +{ + return ::getuid(); +} + +string ProcessInfo::username() +{ + struct passwd pwd; + struct passwd* result = NULL; + char buf[8192]; + const char* name = "unknownuser"; + + getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); + if (result) + { + name = pwd.pw_name; + } + return name; +} + +uid_t ProcessInfo::euid() +{ + return ::geteuid(); +} + +Timestamp ProcessInfo::startTime() +{ + return g_startTime; +} + +int ProcessInfo::clockTicksPerSecond() +{ + return g_clockTicks; +} + +int ProcessInfo::pageSize() +{ + return g_pageSize; +} + +bool ProcessInfo::isDebugBuild() +{ +#ifdef NDEBUG + return false; +#else + return true; +#endif +} + +string ProcessInfo::hostname() +{ + // HOST_NAME_MAX 64 + // _POSIX_HOST_NAME_MAX 255 + char buf[256]; + if (::gethostname(buf, sizeof buf) == 0) + { + buf[sizeof(buf)-1] = '\0'; + return buf; + } + else + { + return "unknownhost"; + } +} + +string ProcessInfo::procname() +{ + return procname(procStat()).as_string(); +} + +StringPiece ProcessInfo::procname(const string& stat) +{ + StringPiece name; + size_t lp = stat.find('('); + size_t rp = stat.rfind(')'); + if (lp != string::npos && rp != string::npos && lp < rp) + { + name.set(stat.data()+lp+1, static_cast(rp-lp-1)); + } + return name; +} + +string ProcessInfo::procStatus() +{ + string result; + FileUtil::readFile("/proc/self/status", 65536, &result); + return result; +} + +string ProcessInfo::procStat() +{ + string result; + FileUtil::readFile("/proc/self/stat", 65536, &result); + return result; +} + +string ProcessInfo::threadStat() +{ + char buf[64]; + snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid()); + string result; + FileUtil::readFile(buf, 65536, &result); + return result; +} + +string ProcessInfo::exePath() +{ + string result; + char buf[1024]; + ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf); + if (n > 0) + { + result.assign(buf, n); + } + return result; +} + +int ProcessInfo::openedFiles() +{ + t_numOpenedFiles = 0; + scanDir("/proc/self/fd", fdDirFilter); + return t_numOpenedFiles; +} + +int ProcessInfo::maxOpenFiles() +{ + struct rlimit rl; + if (::getrlimit(RLIMIT_NOFILE, &rl)) + { + return openedFiles(); + } + else + { + return static_cast(rl.rlim_cur); + } +} + +ProcessInfo::CpuTime ProcessInfo::cpuTime() +{ + ProcessInfo::CpuTime t; + struct tms tms; + if (::times(&tms) >= 0) + { + const double hz = static_cast(clockTicksPerSecond()); + t.userSeconds = static_cast(tms.tms_utime) / hz; + t.systemSeconds = static_cast(tms.tms_stime) / hz; + } + return t; +} + +int ProcessInfo::numThreads() +{ + int result = 0; + string status = procStatus(); + size_t pos = status.find("Threads:"); + if (pos != string::npos) + { + result = ::atoi(status.c_str() + pos + 8); + } + return result; +} + +std::vector ProcessInfo::threads() +{ + std::vector result; + t_pids = &result; + scanDir("/proc/self/task", taskDirFilter); + t_pids = NULL; + std::sort(result.begin(), result.end()); + return result; +} + diff --git a/include/muduo/base/ProcessInfo.h b/include/muduo/base/ProcessInfo.h new file mode 100644 index 0000000..eae1498 --- /dev/null +++ b/include/muduo/base/ProcessInfo.h @@ -0,0 +1,68 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_BASE_PROCESSINFO_H +#define MUDUO_BASE_PROCESSINFO_H + +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include "muduo/base/Timestamp.h" +#include +#include + +namespace muduo +{ + +namespace ProcessInfo +{ + pid_t pid(); + string pidString(); + uid_t uid(); + string username(); + uid_t euid(); + Timestamp startTime(); + int clockTicksPerSecond(); + int pageSize(); + bool isDebugBuild(); // constexpr + + string hostname(); + string procname(); + StringPiece procname(const string& stat); + + /// read /proc/self/status + string procStatus(); + + /// read /proc/self/stat + string procStat(); + + /// read /proc/self/task/tid/stat + string threadStat(); + + /// readlink /proc/self/exe + string exePath(); + + int openedFiles(); + int maxOpenFiles(); + + struct CpuTime + { + double userSeconds; + double systemSeconds; + + CpuTime() : userSeconds(0.0), systemSeconds(0.0) { } + + double total() const { return userSeconds + systemSeconds; } + }; + CpuTime cpuTime(); + + int numThreads(); + std::vector threads(); +} // namespace ProcessInfo + +} // namespace muduo + +#endif // MUDUO_BASE_PROCESSINFO_H diff --git a/include/muduo/base/Singleton.h b/include/muduo/base/Singleton.h new file mode 100644 index 0000000..5949436 --- /dev/null +++ b/include/muduo/base/Singleton.h @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_SINGLETON_H +#define MUDUO_BASE_SINGLETON_H + +#include "muduo/base/noncopyable.h" + +#include +#include +#include // atexit + +namespace muduo +{ + +namespace detail +{ +// This doesn't detect inherited member functions! +// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions +template +struct has_no_destroy +{ + template static char test(decltype(&C::no_destroy)); + template static int32_t test(...); + const static bool value = sizeof(test(0)) == 1; +}; +} // namespace detail + +template +class Singleton : noncopyable +{ + public: + Singleton() = delete; + ~Singleton() = delete; + + static T& instance() + { + pthread_once(&ponce_, &Singleton::init); + assert(value_ != NULL); + return *value_; + } + + private: + static void init() + { + value_ = new T(); + if (!detail::has_no_destroy::value) + { + ::atexit(destroy); + } + } + + static void destroy() + { + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + + delete value_; + value_ = NULL; + } + + private: + static pthread_once_t ponce_; + static T* value_; +}; + +template +pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT; + +template +T* Singleton::value_ = NULL; + +} // namespace muduo + +#endif // MUDUO_BASE_SINGLETON_H diff --git a/include/muduo/base/StringPiece.h b/include/muduo/base/StringPiece.h new file mode 100644 index 0000000..a62eda0 --- /dev/null +++ b/include/muduo/base/StringPiece.h @@ -0,0 +1,189 @@ +// Taken from PCRE pcre_stringpiece.h +// +// Copyright (c) 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Sanjay Ghemawat +// +// A string like object that points into another piece of memory. +// Useful for providing an interface that allows clients to easily +// pass in either a "const char*" or a "string". +// +// Arghh! I wish C++ literals were automatically of type "string". + +#ifndef MUDUO_BASE_STRINGPIECE_H +#define MUDUO_BASE_STRINGPIECE_H + +#include +#include // for ostream forward-declaration + +#include "muduo/base/Types.h" + +namespace muduo +{ + +// For passing C-style string argument to a function. +class StringArg // copyable +{ + public: + StringArg(const char* str) + : str_(str) + { } + + StringArg(const string& str) + : str_(str.c_str()) + { } + + const char* c_str() const { return str_; } + + private: + const char* str_; +}; + +class StringPiece { + private: + const char* ptr_; + int length_; + + public: + // We provide non-explicit singleton constructors so users can pass + // in a "const char*" or a "string" wherever a "StringPiece" is + // expected. + StringPiece() + : ptr_(NULL), length_(0) { } + StringPiece(const char* str) + : ptr_(str), length_(static_cast(strlen(ptr_))) { } + StringPiece(const unsigned char* str) + : ptr_(reinterpret_cast(str)), + length_(static_cast(strlen(ptr_))) { } + StringPiece(const string& str) + : ptr_(str.data()), length_(static_cast(str.size())) { } + StringPiece(const char* offset, int len) + : ptr_(offset), length_(len) { } + + // data() may return a pointer to a buffer with embedded NULs, and the + // returned buffer may or may not be null terminated. Therefore it is + // typically a mistake to pass data() to a routine that expects a NUL + // terminated string. Use "as_string().c_str()" if you really need to do + // this. Or better yet, change your routine so it does not rely on NUL + // termination. + const char* data() const { return ptr_; } + int size() const { return length_; } + bool empty() const { return length_ == 0; } + const char* begin() const { return ptr_; } + const char* end() const { return ptr_ + length_; } + + void clear() { ptr_ = NULL; length_ = 0; } + void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; } + void set(const char* str) { + ptr_ = str; + length_ = static_cast(strlen(str)); + } + void set(const void* buffer, int len) { + ptr_ = reinterpret_cast(buffer); + length_ = len; + } + + char operator[](int i) const { return ptr_[i]; } + + void remove_prefix(int n) { + ptr_ += n; + length_ -= n; + } + + void remove_suffix(int n) { + length_ -= n; + } + + bool operator==(const StringPiece& x) const { + return ((length_ == x.length_) && + (memcmp(ptr_, x.ptr_, length_) == 0)); + } + bool operator!=(const StringPiece& x) const { + return !(*this == x); + } + +#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \ + bool operator cmp (const StringPiece& x) const { \ + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \ + return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \ + } + STRINGPIECE_BINARY_PREDICATE(<, <); + STRINGPIECE_BINARY_PREDICATE(<=, <); + STRINGPIECE_BINARY_PREDICATE(>=, >); + STRINGPIECE_BINARY_PREDICATE(>, >); +#undef STRINGPIECE_BINARY_PREDICATE + + int compare(const StringPiece& x) const { + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); + if (r == 0) { + if (length_ < x.length_) r = -1; + else if (length_ > x.length_) r = +1; + } + return r; + } + + string as_string() const { + return string(data(), size()); + } + + void CopyToString(string* target) const { + target->assign(ptr_, length_); + } + + // Does "this" start with "x" + bool starts_with(const StringPiece& x) const { + return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0)); + } +}; + +} // namespace muduo + +// ------------------------------------------------------------------ +// Functions used to create STL containers that use StringPiece +// Remember that a StringPiece's lifetime had better be less than +// that of the underlying string or char*. If it is not, then you +// cannot safely store a StringPiece into an STL container +// ------------------------------------------------------------------ + +#ifdef HAVE_TYPE_TRAITS +// This makes vector really fast for some STL implementations +template<> struct __type_traits { + typedef __true_type has_trivial_default_constructor; + typedef __true_type has_trivial_copy_constructor; + typedef __true_type has_trivial_assignment_operator; + typedef __true_type has_trivial_destructor; + typedef __true_type is_POD_type; +}; +#endif + +// allow StringPiece to be logged +std::ostream& operator<<(std::ostream& o, const muduo::StringPiece& piece); + +#endif // MUDUO_BASE_STRINGPIECE_H diff --git a/include/muduo/base/Thread.cc b/include/muduo/base/Thread.cc new file mode 100644 index 0000000..630a0c9 --- /dev/null +++ b/include/muduo/base/Thread.cc @@ -0,0 +1,200 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Thread.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Exception.h" +#include "muduo/base/Logging.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace muduo +{ +namespace detail +{ + +pid_t gettid() +{ + return static_cast(::syscall(SYS_gettid)); +} + +void afterFork() +{ + muduo::CurrentThread::t_cachedTid = 0; + muduo::CurrentThread::t_threadName = "main"; + CurrentThread::tid(); + // no need to call pthread_atfork(NULL, NULL, &afterFork); +} + +class ThreadNameInitializer +{ + public: + ThreadNameInitializer() + { + muduo::CurrentThread::t_threadName = "main"; + CurrentThread::tid(); + pthread_atfork(NULL, NULL, &afterFork); + } +}; + +ThreadNameInitializer init; + +struct ThreadData +{ + typedef muduo::Thread::ThreadFunc ThreadFunc; + ThreadFunc func_; + string name_; + pid_t* tid_; + CountDownLatch* latch_; + + ThreadData(ThreadFunc func, + const string& name, + pid_t* tid, + CountDownLatch* latch) + : func_(std::move(func)), + name_(name), + tid_(tid), + latch_(latch) + { } + + void runInThread() + { + *tid_ = muduo::CurrentThread::tid(); + tid_ = NULL; + latch_->countDown(); + latch_ = NULL; + + muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str(); + ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName); + try + { + func_(); + muduo::CurrentThread::t_threadName = "finished"; + } + catch (const Exception& ex) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); + abort(); + } + catch (const std::exception& ex) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + abort(); + } + catch (...) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str()); + throw; // rethrow + } + } +}; + +void* startThread(void* obj) +{ + ThreadData* data = static_cast(obj); + data->runInThread(); + delete data; + return NULL; +} + +} // namespace detail + +void CurrentThread::cacheTid() +{ + if (t_cachedTid == 0) + { + t_cachedTid = detail::gettid(); + t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); + } +} + +bool CurrentThread::isMainThread() +{ + return tid() == ::getpid(); +} + +void CurrentThread::sleepUsec(int64_t usec) +{ + struct timespec ts = { 0, 0 }; + ts.tv_sec = static_cast(usec / Timestamp::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast(usec % Timestamp::kMicroSecondsPerSecond * 1000); + ::nanosleep(&ts, NULL); +} + +AtomicInt32 Thread::numCreated_; + +Thread::Thread(ThreadFunc func, const string& n) + : started_(false), + joined_(false), + pthreadId_(0), + tid_(0), + func_(std::move(func)), + name_(n), + latch_(1) +{ + setDefaultName(); +} + +Thread::~Thread() +{ + if (started_ && !joined_) + { + pthread_detach(pthreadId_); + } +} + +void Thread::setDefaultName() +{ + int num = numCreated_.incrementAndGet(); + if (name_.empty()) + { + char buf[32]; + snprintf(buf, sizeof buf, "Thread%d", num); + name_ = buf; + } +} + +void Thread::start() +{ + assert(!started_); + started_ = true; + // FIXME: move(func_) + detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_); + if (pthread_create(&pthreadId_, NULL, &detail::startThread, data)) + { + started_ = false; + delete data; // or no delete? + LOG_SYSFATAL << "Failed in pthread_create"; + } + else + { + latch_.wait(); + assert(tid_ > 0); + } +} + +int Thread::join() +{ + assert(started_); + assert(!joined_); + joined_ = true; + return pthread_join(pthreadId_, NULL); +} + +} // namespace muduo diff --git a/include/muduo/base/Thread.h b/include/muduo/base/Thread.h new file mode 100644 index 0000000..d2305a2 --- /dev/null +++ b/include/muduo/base/Thread.h @@ -0,0 +1,54 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREAD_H +#define MUDUO_BASE_THREAD_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ + +class Thread : noncopyable +{ + public: + typedef std::function ThreadFunc; + + explicit Thread(ThreadFunc, const string& name = string()); + // FIXME: make it movable in C++11 + ~Thread(); + + void start(); + int join(); // return pthread_join() + + bool started() const { return started_; } + // pthread_t pthreadId() const { return pthreadId_; } + pid_t tid() const { return tid_; } + const string& name() const { return name_; } + + static int numCreated() { return numCreated_.get(); } + + private: + void setDefaultName(); + + bool started_; + bool joined_; + pthread_t pthreadId_; + pid_t tid_; + ThreadFunc func_; + string name_; + CountDownLatch latch_; + + static AtomicInt32 numCreated_; +}; + +} // namespace muduo +#endif // MUDUO_BASE_THREAD_H diff --git a/include/muduo/base/ThreadLocal.h b/include/muduo/base/ThreadLocal.h new file mode 100644 index 0000000..b8283bc --- /dev/null +++ b/include/muduo/base/ThreadLocal.h @@ -0,0 +1,59 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCAL_H +#define MUDUO_BASE_THREADLOCAL_H + +#include "muduo/base/Mutex.h" +#include "muduo/base/noncopyable.h" + +#include + +namespace muduo +{ + +template +class ThreadLocal : noncopyable +{ + public: + ThreadLocal() + { + MCHECK(pthread_key_create(&pkey_, &ThreadLocal::destructor)); + } + + ~ThreadLocal() + { + MCHECK(pthread_key_delete(pkey_)); + } + + T& value() + { + T* perThreadValue = static_cast(pthread_getspecific(pkey_)); + if (!perThreadValue) + { + T* newObj = new T(); + MCHECK(pthread_setspecific(pkey_, newObj)); + perThreadValue = newObj; + } + return *perThreadValue; + } + + private: + + static void destructor(void *x) + { + T* obj = static_cast(x); + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + delete obj; + } + + private: + pthread_key_t pkey_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_THREADLOCAL_H diff --git a/include/muduo/base/ThreadLocalSingleton.h b/include/muduo/base/ThreadLocalSingleton.h new file mode 100644 index 0000000..5c544df --- /dev/null +++ b/include/muduo/base/ThreadLocalSingleton.h @@ -0,0 +1,82 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCALSINGLETON_H +#define MUDUO_BASE_THREADLOCALSINGLETON_H + +#include "muduo/base/noncopyable.h" + +#include +#include + +namespace muduo +{ + +template +class ThreadLocalSingleton : noncopyable +{ + public: + ThreadLocalSingleton() = delete; + ~ThreadLocalSingleton() = delete; + + static T& instance() + { + if (!t_value_) + { + t_value_ = new T(); + deleter_.set(t_value_); + } + return *t_value_; + } + + static T* pointer() + { + return t_value_; + } + + private: + static void destructor(void* obj) + { + assert(obj == t_value_); + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + delete t_value_; + t_value_ = 0; + } + + class Deleter + { + public: + Deleter() + { + pthread_key_create(&pkey_, &ThreadLocalSingleton::destructor); + } + + ~Deleter() + { + pthread_key_delete(pkey_); + } + + void set(T* newObj) + { + assert(pthread_getspecific(pkey_) == NULL); + pthread_setspecific(pkey_, newObj); + } + + pthread_key_t pkey_; + }; + + static __thread T* t_value_; + static Deleter deleter_; +}; + +template +__thread T* ThreadLocalSingleton::t_value_ = 0; + +template +typename ThreadLocalSingleton::Deleter ThreadLocalSingleton::deleter_; + +} // namespace muduo +#endif // MUDUO_BASE_THREADLOCALSINGLETON_H diff --git a/include/muduo/base/ThreadPool.cc b/include/muduo/base/ThreadPool.cc new file mode 100644 index 0000000..6905dd7 --- /dev/null +++ b/include/muduo/base/ThreadPool.cc @@ -0,0 +1,156 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/ThreadPool.h" + +#include "muduo/base/Exception.h" + +#include +#include + +using namespace muduo; + +ThreadPool::ThreadPool(const string& nameArg) + : mutex_(), + notEmpty_(mutex_), + notFull_(mutex_), + name_(nameArg), + maxQueueSize_(0), + running_(false) +{ +} + +ThreadPool::~ThreadPool() +{ + if (running_) + { + stop(); + } +} + +void ThreadPool::start(int numThreads) +{ + assert(threads_.empty()); + running_ = true; + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char id[32]; + snprintf(id, sizeof id, "%d", i+1); + threads_.emplace_back(new muduo::Thread( + std::bind(&ThreadPool::runInThread, this), name_+id)); + threads_[i]->start(); + } + if (numThreads == 0 && threadInitCallback_) + { + threadInitCallback_(); + } +} + +void ThreadPool::stop() +{ + { + MutexLockGuard lock(mutex_); + running_ = false; + notEmpty_.notifyAll(); + notFull_.notifyAll(); + } + for (auto& thr : threads_) + { + thr->join(); + } +} + +size_t ThreadPool::queueSize() const +{ + MutexLockGuard lock(mutex_); + return queue_.size(); +} + +void ThreadPool::run(Task task) +{ + if (threads_.empty()) + { + task(); + } + else + { + MutexLockGuard lock(mutex_); + while (isFull() && running_) + { + notFull_.wait(); + } + if (!running_) return; + assert(!isFull()); + + queue_.push_back(std::move(task)); + notEmpty_.notify(); + } +} + +ThreadPool::Task ThreadPool::take() +{ + MutexLockGuard lock(mutex_); + // always use a while-loop, due to spurious wakeup + while (queue_.empty() && running_) + { + notEmpty_.wait(); + } + Task task; + if (!queue_.empty()) + { + task = queue_.front(); + queue_.pop_front(); + if (maxQueueSize_ > 0) + { + notFull_.notify(); + } + } + return task; +} + +bool ThreadPool::isFull() const +{ + mutex_.assertLocked(); + return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_; +} + +void ThreadPool::runInThread() +{ + try + { + if (threadInitCallback_) + { + threadInitCallback_(); + } + while (running_) + { + Task task(take()); + if (task) + { + task(); + } + } + } + catch (const Exception& ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); + abort(); + } + catch (const std::exception& ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + abort(); + } + catch (...) + { + fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str()); + throw; // rethrow + } +} + diff --git a/include/muduo/base/ThreadPool.h b/include/muduo/base/ThreadPool.h new file mode 100644 index 0000000..385c1bb --- /dev/null +++ b/include/muduo/base/ThreadPool.h @@ -0,0 +1,67 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADPOOL_H +#define MUDUO_BASE_THREADPOOL_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Types.h" + +#include +#include + +namespace muduo +{ + +class ThreadPool : noncopyable +{ + public: + typedef std::function Task; + + explicit ThreadPool(const string& nameArg = string("ThreadPool")); + ~ThreadPool(); + + // Must be called before start(). + void setMaxQueueSize(int maxSize) { maxQueueSize_ = maxSize; } + void setThreadInitCallback(const Task& cb) + { threadInitCallback_ = cb; } + + void start(int numThreads); + void stop(); + + const string& name() const + { return name_; } + + size_t queueSize() const; + + // Could block if maxQueueSize > 0 + // Call after stop() will return immediately. + // There is no move-only version of std::function in C++ as of C++14. + // So we don't need to overload a const& and an && versions + // as we do in (Bounded)BlockingQueue. + // https://stackoverflow.com/a/25408989 + void run(Task f); + + private: + bool isFull() const REQUIRES(mutex_); + void runInThread(); + Task take(); + + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + Condition notFull_ GUARDED_BY(mutex_); + string name_; + Task threadInitCallback_; + std::vector> threads_; + std::deque queue_ GUARDED_BY(mutex_); + size_t maxQueueSize_; + bool running_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_THREADPOOL_H diff --git a/include/muduo/base/TimeZone.cc b/include/muduo/base/TimeZone.cc new file mode 100644 index 0000000..9544385 --- /dev/null +++ b/include/muduo/base/TimeZone.cc @@ -0,0 +1,363 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/TimeZone.h" +#include "muduo/base/noncopyable.h" +#include "muduo/base/Date.h" + +#include +#include +#include +#include + +#include +//#define _BSD_SOURCE +#include + +#include +#include + +namespace muduo +{ +namespace detail +{ + +struct Transition +{ + time_t gmttime; + time_t localtime; + int localtimeIdx; + + Transition(time_t t, time_t l, int localIdx) + : gmttime(t), localtime(l), localtimeIdx(localIdx) + { } + +}; + +struct Comp +{ + bool compareGmt; + + Comp(bool gmt) + : compareGmt(gmt) + { + } + + bool operator()(const Transition& lhs, const Transition& rhs) const + { + if (compareGmt) + return lhs.gmttime < rhs.gmttime; + else + return lhs.localtime < rhs.localtime; + } + + bool equal(const Transition& lhs, const Transition& rhs) const + { + if (compareGmt) + return lhs.gmttime == rhs.gmttime; + else + return lhs.localtime == rhs.localtime; + } +}; + +struct Localtime +{ + time_t gmtOffset; + bool isDst; + int arrbIdx; + + Localtime(time_t offset, bool dst, int arrb) + : gmtOffset(offset), isDst(dst), arrbIdx(arrb) + { } +}; + +inline void fillHMS(unsigned seconds, struct tm* utc) +{ + utc->tm_sec = seconds % 60; + unsigned minutes = seconds / 60; + utc->tm_min = minutes % 60; + utc->tm_hour = minutes / 60; +} + +} // namespace detail +const int kSecondsPerDay = 24*60*60; +} // namespace muduo + +using namespace muduo; +using namespace std; + +struct TimeZone::Data +{ + vector transitions; + vector localtimes; + vector names; + string abbreviation; +}; + +namespace muduo +{ +namespace detail +{ + +class File : noncopyable +{ + public: + File(const char* file) + : fp_(::fopen(file, "rb")) + { + } + + ~File() + { + if (fp_) + { + ::fclose(fp_); + } + } + + bool valid() const { return fp_; } + + string readBytes(int n) + { + char buf[n]; + ssize_t nr = ::fread(buf, 1, n, fp_); + if (nr != n) + throw logic_error("no enough data"); + return string(buf, n); + } + + int32_t readInt32() + { + int32_t x = 0; + ssize_t nr = ::fread(&x, 1, sizeof(int32_t), fp_); + if (nr != sizeof(int32_t)) + throw logic_error("bad int32_t data"); + return be32toh(x); + } + + uint8_t readUInt8() + { + uint8_t x = 0; + ssize_t nr = ::fread(&x, 1, sizeof(uint8_t), fp_); + if (nr != sizeof(uint8_t)) + throw logic_error("bad uint8_t data"); + return x; + } + + private: + FILE* fp_; +}; + +bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) +{ + File f(zonefile); + if (f.valid()) + { + try + { + string head = f.readBytes(4); + if (head != "TZif") + throw logic_error("bad head"); + string version = f.readBytes(1); + f.readBytes(15); + + int32_t isgmtcnt = f.readInt32(); + int32_t isstdcnt = f.readInt32(); + int32_t leapcnt = f.readInt32(); + int32_t timecnt = f.readInt32(); + int32_t typecnt = f.readInt32(); + int32_t charcnt = f.readInt32(); + + vector trans; + vector localtimes; + trans.reserve(timecnt); + for (int i = 0; i < timecnt; ++i) + { + trans.push_back(f.readInt32()); + } + + for (int i = 0; i < timecnt; ++i) + { + uint8_t local = f.readUInt8(); + localtimes.push_back(local); + } + + for (int i = 0; i < typecnt; ++i) + { + int32_t gmtoff = f.readInt32(); + uint8_t isdst = f.readUInt8(); + uint8_t abbrind = f.readUInt8(); + + data->localtimes.push_back(Localtime(gmtoff, isdst, abbrind)); + } + + for (int i = 0; i < timecnt; ++i) + { + int localIdx = localtimes[i]; + time_t localtime = trans[i] + data->localtimes[localIdx].gmtOffset; + data->transitions.push_back(Transition(trans[i], localtime, localIdx)); + } + + data->abbreviation = f.readBytes(charcnt); + + // leapcnt + for (int i = 0; i < leapcnt; ++i) + { + // int32_t leaptime = f.readInt32(); + // int32_t cumleap = f.readInt32(); + } + // FIXME + (void) isstdcnt; + (void) isgmtcnt; + } + catch (logic_error& e) + { + fprintf(stderr, "%s\n", e.what()); + } + } + return true; +} + +const Localtime* findLocaltime(const TimeZone::Data& data, Transition sentry, Comp comp) +{ + const Localtime* local = NULL; + + if (data.transitions.empty() || comp(sentry, data.transitions.front())) + { + // FIXME: should be first non dst time zone + local = &data.localtimes.front(); + } + else + { + vector::const_iterator transI = lower_bound(data.transitions.begin(), + data.transitions.end(), + sentry, + comp); + if (transI != data.transitions.end()) + { + if (!comp.equal(sentry, *transI)) + { + assert(transI != data.transitions.begin()); + --transI; + } + local = &data.localtimes[transI->localtimeIdx]; + } + else + { + // FIXME: use TZ-env + local = &data.localtimes[data.transitions.back().localtimeIdx]; + } + } + + return local; +} + +} // namespace detail +} // namespace muduo + + +TimeZone::TimeZone(const char* zonefile) + : data_(new TimeZone::Data) +{ + if (!detail::readTimeZoneFile(zonefile, data_.get())) + { + data_.reset(); + } +} + +TimeZone::TimeZone(int eastOfUtc, const char* name) + : data_(new TimeZone::Data) +{ + data_->localtimes.push_back(detail::Localtime(eastOfUtc, false, 0)); + data_->abbreviation = name; +} + +struct tm TimeZone::toLocalTime(time_t seconds) const +{ + struct tm localTime; + memZero(&localTime, sizeof(localTime)); + assert(data_ != NULL); + const Data& data(*data_); + + detail::Transition sentry(seconds, 0, 0); + const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(true)); + + if (local) + { + time_t localSeconds = seconds + local->gmtOffset; + ::gmtime_r(&localSeconds, &localTime); // FIXME: fromUtcTime + localTime.tm_isdst = local->isDst; + localTime.tm_gmtoff = local->gmtOffset; + localTime.tm_zone = &data.abbreviation[local->arrbIdx]; + } + + return localTime; +} + +time_t TimeZone::fromLocalTime(const struct tm& localTm) const +{ + assert(data_ != NULL); + const Data& data(*data_); + + struct tm tmp = localTm; + time_t seconds = ::timegm(&tmp); // FIXME: toUtcTime + detail::Transition sentry(0, seconds, 0); + const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(false)); + if (localTm.tm_isdst) + { + struct tm tryTm = toLocalTime(seconds - local->gmtOffset); + if (!tryTm.tm_isdst + && tryTm.tm_hour == localTm.tm_hour + && tryTm.tm_min == localTm.tm_min) + { + // FIXME: HACK + seconds -= 3600; + } + } + return seconds - local->gmtOffset; +} + +struct tm TimeZone::toUtcTime(time_t secondsSinceEpoch, bool yday) +{ + struct tm utc; + memZero(&utc, sizeof(utc)); + utc.tm_zone = "GMT"; + int seconds = static_cast(secondsSinceEpoch % kSecondsPerDay); + int days = static_cast(secondsSinceEpoch / kSecondsPerDay); + if (seconds < 0) + { + seconds += kSecondsPerDay; + --days; + } + detail::fillHMS(seconds, &utc); + Date date(days + Date::kJulianDayOf1970_01_01); + Date::YearMonthDay ymd = date.yearMonthDay(); + utc.tm_year = ymd.year - 1900; + utc.tm_mon = ymd.month - 1; + utc.tm_mday = ymd.day; + utc.tm_wday = date.weekDay(); + + if (yday) + { + Date startOfYear(ymd.year, 1, 1); + utc.tm_yday = date.julianDayNumber() - startOfYear.julianDayNumber(); + } + return utc; +} + +time_t TimeZone::fromUtcTime(const struct tm& utc) +{ + return fromUtcTime(utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, + utc.tm_hour, utc.tm_min, utc.tm_sec); +} + +time_t TimeZone::fromUtcTime(int year, int month, int day, + int hour, int minute, int seconds) +{ + Date date(year, month, day); + int secondsInDay = hour * 3600 + minute * 60 + seconds; + time_t days = date.julianDayNumber() - Date::kJulianDayOf1970_01_01; + return days * kSecondsPerDay + secondsInDay; +} diff --git a/include/muduo/base/TimeZone.h b/include/muduo/base/TimeZone.h new file mode 100644 index 0000000..6586630 --- /dev/null +++ b/include/muduo/base/TimeZone.h @@ -0,0 +1,52 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_TIMEZONE_H +#define MUDUO_BASE_TIMEZONE_H + +#include "muduo/base/copyable.h" +#include +#include + +namespace muduo +{ + +// TimeZone for 1970~2030 +class TimeZone : public muduo::copyable +{ + public: + explicit TimeZone(const char* zonefile); + TimeZone(int eastOfUtc, const char* tzname); // a fixed timezone + TimeZone() = default; // an invalid timezone + + // default copy ctor/assignment/dtor are Okay. + + bool valid() const + { + // 'explicit operator bool() const' in C++11 + return static_cast(data_); + } + + struct tm toLocalTime(time_t secondsSinceEpoch) const; + time_t fromLocalTime(const struct tm&) const; + + // gmtime(3) + static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); + // timegm(3) + static time_t fromUtcTime(const struct tm&); + // year in [1900..2500], month in [1..12], day in [1..31] + static time_t fromUtcTime(int year, int month, int day, + int hour, int minute, int seconds); + + struct Data; + + private: + + std::shared_ptr data_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_TIMEZONE_H diff --git a/include/muduo/base/Timestamp.cc b/include/muduo/base/Timestamp.cc new file mode 100644 index 0000000..fc0ed70 --- /dev/null +++ b/include/muduo/base/Timestamp.cc @@ -0,0 +1,62 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Timestamp.h" + +#include +#include + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include + +using namespace muduo; + +static_assert(sizeof(Timestamp) == sizeof(int64_t), + "Timestamp should be same size as int64_t"); + +string Timestamp::toString() const +{ + char buf[32] = {0}; + int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; + int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; + snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, microseconds); + return buf; +} + +string Timestamp::toFormattedString(bool showMicroseconds) const +{ + char buf[64] = {0}; + time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); + struct tm tm_time; + gmtime_r(&seconds, &tm_time); + + if (showMicroseconds) + { + int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond); + snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, + microseconds); + } + else + { + snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + } + return buf; +} + +Timestamp Timestamp::now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t seconds = tv.tv_sec; + return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); +} + diff --git a/include/muduo/base/Timestamp.h b/include/muduo/base/Timestamp.h new file mode 100644 index 0000000..ccb522d --- /dev/null +++ b/include/muduo/base/Timestamp.h @@ -0,0 +1,123 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_TIMESTAMP_H +#define MUDUO_BASE_TIMESTAMP_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ + +/// +/// Time stamp in UTC, in microseconds resolution. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// +class Timestamp : public muduo::copyable, + public boost::equality_comparable, + public boost::less_than_comparable +{ + public: + /// + /// Constucts an invalid Timestamp. + /// + Timestamp() + : microSecondsSinceEpoch_(0) + { + } + + /// + /// Constucts a Timestamp at specific time + /// + /// @param microSecondsSinceEpoch + explicit Timestamp(int64_t microSecondsSinceEpochArg) + : microSecondsSinceEpoch_(microSecondsSinceEpochArg) + { + } + + void swap(Timestamp& that) + { + std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); + } + + // default copy/assignment/dtor are Okay + + string toString() const; + string toFormattedString(bool showMicroseconds = true) const; + + bool valid() const { return microSecondsSinceEpoch_ > 0; } + + // for internal usage. + int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } + time_t secondsSinceEpoch() const + { return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); } + + /// + /// Get time of now. + /// + static Timestamp now(); + static Timestamp invalid() + { + return Timestamp(); + } + + static Timestamp fromUnixTime(time_t t) + { + return fromUnixTime(t, 0); + } + + static Timestamp fromUnixTime(time_t t, int microseconds) + { + return Timestamp(static_cast(t) * kMicroSecondsPerSecond + microseconds); + } + + static const int kMicroSecondsPerSecond = 1000 * 1000; + + private: + int64_t microSecondsSinceEpoch_; +}; + +inline bool operator<(Timestamp lhs, Timestamp rhs) +{ + return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); +} + +inline bool operator==(Timestamp lhs, Timestamp rhs) +{ + return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); +} + +/// +/// Gets time difference of two timestamps, result in seconds. +/// +/// @param high, low +/// @return (high-low) in seconds +/// @c double has 52-bit precision, enough for one-microsecond +/// resolution for next 100 years. +inline double timeDifference(Timestamp high, Timestamp low) +{ + int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); + return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; +} + +/// +/// Add @c seconds to given timestamp. +/// +/// @return timestamp+seconds as Timestamp +/// +inline Timestamp addTime(Timestamp timestamp, double seconds) +{ + int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); + return Timestamp(timestamp.microSecondsSinceEpoch() + delta); +} + +} // namespace muduo + +#endif // MUDUO_BASE_TIMESTAMP_H diff --git a/include/muduo/base/Types.h b/include/muduo/base/Types.h new file mode 100644 index 0000000..ad94756 --- /dev/null +++ b/include/muduo/base/Types.h @@ -0,0 +1,123 @@ +#ifndef MUDUO_BASE_TYPES_H +#define MUDUO_BASE_TYPES_H + +#include +#include // memset +#include + +#ifndef NDEBUG +#include +#endif + +/// +/// The most common stuffs. +/// +namespace muduo +{ + +using std::string; + +inline void memZero(void* p, size_t n) +{ + memset(p, 0, n); +} + +// Taken from google-protobuf stubs/common.h +// +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) and others +// +// Contains basic types and utilities used by the rest of the library. + +// +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) +{ + return f; +} + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. + +template // use like this: down_cast(foo); +inline To down_cast(From* f) // so we only accept pointers +{ + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) + { + implicit_cast(0); + } + +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) + assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif + return static_cast(f); +} + +} // namespace muduo + +#endif // MUDUO_BASE_TYPES_H diff --git a/include/muduo/base/WeakCallback.h b/include/muduo/base/WeakCallback.h new file mode 100644 index 0000000..5e4650c --- /dev/null +++ b/include/muduo/base/WeakCallback.h @@ -0,0 +1,65 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_WEAKCALLBACK_H +#define MUDUO_BASE_WEAKCALLBACK_H + +#include +#include + +namespace muduo +{ + +// A barely usable WeakCallback + +template +class WeakCallback +{ + public: + + WeakCallback(const std::weak_ptr& object, + const std::function& function) + : object_(object), function_(function) + { + } + + // Default dtor, copy ctor and assignment are okay + + void operator()(ARGS&&... args) const + { + std::shared_ptr ptr(object_.lock()); + if (ptr) + { + function_(ptr.get(), std::forward(args)...); + } + // else + // { + // LOG_TRACE << "expired"; + // } + } + + private: + + std::weak_ptr object_; + std::function function_; +}; + +template +WeakCallback makeWeakCallback(const std::shared_ptr& object, + void (CLASS::*function)(ARGS...)) +{ + return WeakCallback(object, function); +} + +template +WeakCallback makeWeakCallback(const std::shared_ptr& object, + void (CLASS::*function)(ARGS...) const) +{ + return WeakCallback(object, function); +} + +} // namespace muduo + +#endif // MUDUO_BASE_WEAKCALLBACK_H diff --git a/include/muduo/base/copyable.h b/include/muduo/base/copyable.h new file mode 100644 index 0000000..352b287 --- /dev/null +++ b/include/muduo/base/copyable.h @@ -0,0 +1,19 @@ +#ifndef MUDUO_BASE_COPYABLE_H +#define MUDUO_BASE_COPYABLE_H + +namespace muduo +{ + +/// A tag class emphasises the objects are copyable. +/// The empty base class optimization applies. +/// Any derived class of copyable should be a value type. +class copyable +{ + protected: + copyable() = default; + ~copyable() = default; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_COPYABLE_H diff --git a/include/muduo/base/noncopyable.h b/include/muduo/base/noncopyable.h new file mode 100644 index 0000000..79931f9 --- /dev/null +++ b/include/muduo/base/noncopyable.h @@ -0,0 +1,20 @@ +#ifndef MUDUO_BASE_NONCOPYABLE_H +#define MUDUO_BASE_NONCOPYABLE_H + +namespace muduo +{ + +class noncopyable +{ + public: + noncopyable(const noncopyable&) = delete; + void operator=(const noncopyable&) = delete; + + protected: + noncopyable() = default; + ~noncopyable() = default; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_NONCOPYABLE_H diff --git a/include/muduo/base/tests/AsyncLogging_test.cc b/include/muduo/base/tests/AsyncLogging_test.cc new file mode 100644 index 0000000..ad6fde4 --- /dev/null +++ b/include/muduo/base/tests/AsyncLogging_test.cc @@ -0,0 +1,64 @@ +#include "muduo/base/AsyncLogging.h" +#include "muduo/base/Logging.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include + +off_t kRollSize = 500*1000*1000; + +muduo::AsyncLogging* g_asyncLog = NULL; + +void asyncOutput(const char* msg, int len) +{ + g_asyncLog->append(msg, len); +} + +void bench(bool longLog) +{ + muduo::Logger::setOutput(asyncOutput); + + int cnt = 0; + const int kBatch = 1000; + muduo::string empty = " "; + muduo::string longStr(3000, 'X'); + longStr += " "; + + for (int t = 0; t < 30; ++t) + { + muduo::Timestamp start = muduo::Timestamp::now(); + for (int i = 0; i < kBatch; ++i) + { + LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz " + << (longLog ? longStr : empty) + << cnt; + ++cnt; + } + muduo::Timestamp end = muduo::Timestamp::now(); + printf("%f\n", timeDifference(end, start)*1000000/kBatch); + struct timespec ts = { 0, 500*1000*1000 }; + nanosleep(&ts, NULL); + } +} + +int main(int argc, char* argv[]) +{ + { + // set max virtual memory to 2GB. + size_t kOneGB = 1000*1024*1024; + rlimit rl = { 2*kOneGB, 2*kOneGB }; + setrlimit(RLIMIT_AS, &rl); + } + + printf("pid = %d\n", getpid()); + + char name[256] = { '\0' }; + strncpy(name, argv[0], sizeof name - 1); + muduo::AsyncLogging log(::basename(name), kRollSize); + log.start(); + g_asyncLog = &log; + + bool longLog = argc > 1; + bench(longLog); +} diff --git a/include/muduo/base/tests/Atomic_unittest.cc b/include/muduo/base/tests/Atomic_unittest.cc new file mode 100644 index 0000000..11d6107 --- /dev/null +++ b/include/muduo/base/tests/Atomic_unittest.cc @@ -0,0 +1,38 @@ +#include "muduo/base/Atomic.h" +#include + +int main() +{ + { + muduo::AtomicInt64 a0; + assert(a0.get() == 0); + assert(a0.getAndAdd(1) == 0); + assert(a0.get() == 1); + assert(a0.addAndGet(2) == 3); + assert(a0.get() == 3); + assert(a0.incrementAndGet() == 4); + assert(a0.get() == 4); + a0.increment(); + assert(a0.get() == 5); + assert(a0.addAndGet(-3) == 2); + assert(a0.getAndSet(100) == 2); + assert(a0.get() == 100); + } + + { + muduo::AtomicInt32 a1; + assert(a1.get() == 0); + assert(a1.getAndAdd(1) == 0); + assert(a1.get() == 1); + assert(a1.addAndGet(2) == 3); + assert(a1.get() == 3); + assert(a1.incrementAndGet() == 4); + assert(a1.get() == 4); + a1.increment(); + assert(a1.get() == 5); + assert(a1.addAndGet(-3) == 2); + assert(a1.getAndSet(100) == 2); + assert(a1.get() == 100); + } +} + diff --git a/include/muduo/base/tests/BlockingQueue_bench.cc b/include/muduo/base/tests/BlockingQueue_bench.cc new file mode 100644 index 0000000..bd65bfa --- /dev/null +++ b/include/muduo/base/tests/BlockingQueue_bench.cc @@ -0,0 +1,106 @@ +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include +#include +#include + +class Bench +{ + public: + Bench(int numThreads) + : latch_(numThreads) + { + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Bench::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + muduo::Timestamp now(muduo::Timestamp::now()); + queue_.put(now); + usleep(1000); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put(muduo::Timestamp::invalid()); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + std::map delays; + latch_.countDown(); + bool running = true; + while (running) + { + muduo::Timestamp t(queue_.take()); + muduo::Timestamp now(muduo::Timestamp::now()); + if (t.valid()) + { + int delay = static_cast(timeDifference(now, t) * 1000000); + // printf("tid=%d, latency = %d us\n", + // muduo::CurrentThread::tid(), delay); + ++delays[delay]; + } + running = t.valid(); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + for (const auto& delay : delays) + { + printf("tid = %d, delay = %d, count = %d\n", + muduo::CurrentThread::tid(), + delay.first, delay.second); + } + } + + muduo::BlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +int main(int argc, char* argv[]) +{ + int threads = argc > 1 ? atoi(argv[1]) : 1; + + Bench t(threads); + t.run(10000); + t.joinAll(); +} diff --git a/include/muduo/base/tests/BlockingQueue_test.cc b/include/muduo/base/tests/BlockingQueue_test.cc new file mode 100644 index 0000000..413fbd2 --- /dev/null +++ b/include/muduo/base/tests/BlockingQueue_test.cc @@ -0,0 +1,106 @@ +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" + +#include +#include +#include +#include +#include + +class Test +{ + public: + Test(int numThreads) + : latch_(numThreads) + { + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Test::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "hello %d", i); + queue_.put(buf); + printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put("stop"); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + latch_.countDown(); + bool running = true; + while (running) + { + std::string d(queue_.take()); + printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); + running = (d != "stop"); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + } + + muduo::BlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +void testMove() +{ + muduo::BlockingQueue> queue; + queue.put(std::unique_ptr(new int(42))); + std::unique_ptr x = queue.take(); + printf("took %d\n", *x); + *x = 123; + queue.put(std::move(x)); + std::unique_ptr y = queue.take(); + printf("took %d\n", *y); +} + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + Test t(5); + t.run(100); + t.joinAll(); + + testMove(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/muduo/base/tests/BoundedBlockingQueue_test.cc b/include/muduo/base/tests/BoundedBlockingQueue_test.cc new file mode 100644 index 0000000..49f57fb --- /dev/null +++ b/include/muduo/base/tests/BoundedBlockingQueue_test.cc @@ -0,0 +1,110 @@ +#include "muduo/base/BoundedBlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" + +#include +#include + +#include +#include + +class Test +{ + public: + Test(int numThreads) + : queue_(20), + latch_(numThreads) + { + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Test::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "hello %d", i); + queue_.put(buf); + printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put("stop"); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + latch_.countDown(); + bool running = true; + while (running) + { + std::string d(queue_.take()); + printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); + running = (d != "stop"); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + } + + muduo::BoundedBlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +void testMove() +{ +#if BOOST_VERSION >= 105500L + muduo::BoundedBlockingQueue> queue(10); + queue.put(std::unique_ptr(new int(42))); + std::unique_ptr x = queue.take(); + printf("took %d\n", *x); + *x = 123; + queue.put(std::move(x)); + std::unique_ptr y; + y = queue.take(); + printf("took %d\n", *y); +#endif +} + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + testMove(); + Test t(5); + t.run(100); + t.joinAll(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/muduo/base/tests/CMakeLists.txt b/include/muduo/base/tests/CMakeLists.txt new file mode 100644 index 0000000..01a1c7a --- /dev/null +++ b/include/muduo/base/tests/CMakeLists.txt @@ -0,0 +1,86 @@ +add_executable(asynclogging_test AsyncLogging_test.cc) +target_link_libraries(asynclogging_test muduo_base) + +add_executable(atomic_unittest Atomic_unittest.cc) +add_test(NAME atomic_unittest COMMAND atomic_unittest) + +add_executable(blockingqueue_test BlockingQueue_test.cc) +target_link_libraries(blockingqueue_test muduo_base) + +add_executable(blockingqueue_bench BlockingQueue_bench.cc) +target_link_libraries(blockingqueue_bench muduo_base) + +add_executable(boundedblockingqueue_test BoundedBlockingQueue_test.cc) +target_link_libraries(boundedblockingqueue_test muduo_base) + +add_executable(date_unittest Date_unittest.cc) +target_link_libraries(date_unittest muduo_base) +add_test(NAME date_unittest COMMAND date_unittest) + +add_executable(exception_test Exception_test.cc) +target_link_libraries(exception_test muduo_base) +add_test(NAME exception_test COMMAND exception_test) + +add_executable(fileutil_test FileUtil_test.cc) +target_link_libraries(fileutil_test muduo_base) +add_test(NAME fileutil_test COMMAND fileutil_test) + +add_executable(fork_test Fork_test.cc) +target_link_libraries(fork_test muduo_base) + +if(ZLIB_FOUND) + add_executable(gzipfile_test GzipFile_test.cc) + target_link_libraries(gzipfile_test muduo_base z) + add_test(NAME gzipfile_test COMMAND gzipfile_test) +endif() + +add_executable(logfile_test LogFile_test.cc) +target_link_libraries(logfile_test muduo_base) + +add_executable(logging_test Logging_test.cc) +target_link_libraries(logging_test muduo_base) + +add_executable(logstream_bench LogStream_bench.cc) +target_link_libraries(logstream_bench muduo_base) + +if(BOOSTTEST_LIBRARY) +add_executable(logstream_test LogStream_test.cc) +target_link_libraries(logstream_test muduo_base boost_unit_test_framework) +add_test(NAME logstream_test COMMAND logstream_test) +endif() + +add_executable(mutex_test Mutex_test.cc) +target_link_libraries(mutex_test muduo_base) + +add_executable(processinfo_test ProcessInfo_test.cc) +target_link_libraries(processinfo_test muduo_base) + +add_executable(singleton_test Singleton_test.cc) +target_link_libraries(singleton_test muduo_base) + +add_executable(singleton_threadlocal_test SingletonThreadLocal_test.cc) +target_link_libraries(singleton_threadlocal_test muduo_base) + +add_executable(thread_bench Thread_bench.cc) +target_link_libraries(thread_bench muduo_base) + +add_executable(thread_test Thread_test.cc) +target_link_libraries(thread_test muduo_base) + +add_executable(threadlocal_test ThreadLocal_test.cc) +target_link_libraries(threadlocal_test muduo_base) + +add_executable(threadlocalsingleton_test ThreadLocalSingleton_test.cc) +target_link_libraries(threadlocalsingleton_test muduo_base) + +add_executable(threadpool_test ThreadPool_test.cc) +target_link_libraries(threadpool_test muduo_base) + +add_executable(timestamp_unittest Timestamp_unittest.cc) +target_link_libraries(timestamp_unittest muduo_base) +add_test(NAME timestamp_unittest COMMAND timestamp_unittest) + +add_executable(timezone_unittest TimeZone_unittest.cc) +target_link_libraries(timezone_unittest muduo_base) +add_test(NAME timezone_unittest COMMAND timezone_unittest) + diff --git a/include/muduo/base/tests/Date_unittest.cc b/include/muduo/base/tests/Date_unittest.cc new file mode 100644 index 0000000..bf2d386 --- /dev/null +++ b/include/muduo/base/tests/Date_unittest.cc @@ -0,0 +1,88 @@ +#include "muduo/base/Date.h" +#include +#include + +using muduo::Date; + +const int kMonthsOfYear = 12; + +int isLeapYear(int year) +{ + if (year % 400 == 0) + return 1; + else if (year % 100 == 0) + return 0; + else if (year % 4 == 0) + return 1; + else + return 0; +} + +int daysOfMonth(int year, int month) +{ + static int days[2][kMonthsOfYear+1] = + { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + }; + return days[isLeapYear(year)][month]; +} + +void passByConstReference(const Date& x) +{ + printf("%s\n", x.toIsoString().c_str()); +} + +void passByValue(Date x) +{ + printf("%s\n", x.toIsoString().c_str()); +} + +int main() +{ + time_t now = time(NULL); + struct tm t1 = *gmtime(&now); + struct tm t2 = *localtime(&now); + Date someDay(2008, 9, 10); + printf("%s\n", someDay.toIsoString().c_str()); + passByValue(someDay); + passByConstReference(someDay); + Date todayUtc(t1); + printf("%s\n", todayUtc.toIsoString().c_str()); + Date todayLocal(t2); + printf("%s\n", todayLocal.toIsoString().c_str()); + + int julianDayNumber = 2415021; + int weekDay = 1; // Monday + + for (int year = 1900; year < 2500; ++year) + { + assert(Date(year, 3, 1).julianDayNumber() - Date(year, 2, 29).julianDayNumber() + == isLeapYear(year)); + for (int month = 1; month <= kMonthsOfYear; ++month) + { + for (int day = 1; day <= daysOfMonth(year, month); ++day) + { + Date d(year, month, day); + // printf("%s %d\n", d.toString().c_str(), d.weekDay()); + assert(year == d.year()); + assert(month == d.month()); + assert(day == d.day()); + assert(weekDay == d.weekDay()); + assert(julianDayNumber == d.julianDayNumber()); + + Date d2(julianDayNumber); + assert(year == d2.year()); + assert(month == d2.month()); + assert(day == d2.day()); + assert(weekDay == d2.weekDay()); + assert(julianDayNumber == d2.julianDayNumber()); + + ++julianDayNumber; + weekDay = (weekDay+1) % 7; + } + } + } + printf("All passed.\n"); +} + diff --git a/include/muduo/base/tests/Exception_test.cc b/include/muduo/base/tests/Exception_test.cc new file mode 100644 index 0000000..7fd8004 --- /dev/null +++ b/include/muduo/base/tests/Exception_test.cc @@ -0,0 +1,51 @@ +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Exception.h" +#include +#include +#include + +class Bar +{ + public: + void test(std::vector names = {}) + { + printf("Stack:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + [] { + printf("Stack inside lambda:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + }(); + std::function func([] { + printf("Stack inside std::function:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + }); + func(); + + func = std::bind(&Bar::callback, this); + func(); + + throw muduo::Exception("oops"); + } + + private: + void callback() + { + printf("Stack inside std::bind:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + } +}; + +void foo() +{ + Bar b; + b.test(); +} + +int main() +{ + try + { + foo(); + } + catch (const muduo::Exception& ex) + { + printf("reason: %s\n", ex.what()); + printf("stack trace:\n%s\n", ex.stackTrace()); + } +} diff --git a/include/muduo/base/tests/FileUtil_test.cc b/include/muduo/base/tests/FileUtil_test.cc new file mode 100644 index 0000000..9abe299 --- /dev/null +++ b/include/muduo/base/tests/FileUtil_test.cc @@ -0,0 +1,30 @@ +#include "muduo/base/FileUtil.h" + +#include +#define __STDC_FORMAT_MACROS +#include + +using namespace muduo; + +int main() +{ + string result; + int64_t size = 0; + int err = FileUtil::readFile("/proc/self", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/proc/self", 1024, &result, NULL); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/proc/self/cmdline", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/null", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/notexist", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 102400, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 102400, &result, NULL); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); +} + diff --git a/include/muduo/base/tests/Fork_test.cc b/include/muduo/base/tests/Fork_test.cc new file mode 100644 index 0000000..6a3cba6 --- /dev/null +++ b/include/muduo/base/tests/Fork_test.cc @@ -0,0 +1,46 @@ +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +namespace +{ +__thread int x = 0; +} + +void print() +{ + printf("pid=%d tid=%d x=%d\n", getpid(), muduo::CurrentThread::tid(), x); +} + +int main() +{ + printf("parent %d\n", getpid()); + print(); + x = 1; + print(); + pid_t p = fork(); + + if (p == 0) + { + printf("chlid %d\n", getpid()); + // child + print(); + x = 2; + print(); + + if (fork() == 0) + { + printf("grandchlid %d\n", getpid()); + print(); + x = 3; + print(); + } + } + else + { + // parent + print(); + } +} diff --git a/include/muduo/base/tests/GzipFile_test.cc b/include/muduo/base/tests/GzipFile_test.cc new file mode 100644 index 0000000..d3f9cc3 --- /dev/null +++ b/include/muduo/base/tests/GzipFile_test.cc @@ -0,0 +1,54 @@ +#include "muduo/base/GzipFile.h" + +#include "muduo/base/Logging.h" + +int main() +{ + const char* filename = "/tmp/gzipfile_test.gz"; + ::unlink(filename); + const char data[] = "123456789012345678901234567890123456789012345678901234567890\n"; + { + muduo::GzipFile writer = muduo::GzipFile::openForAppend(filename); + if (writer.valid()) + { + LOG_INFO << "tell " << writer.tell(); + LOG_INFO << "wrote " << writer.write(data); + LOG_INFO << "tell " << writer.tell(); + } + } + + { + printf("testing reader\n"); + muduo::GzipFile reader = muduo::GzipFile::openForRead(filename); + if (reader.valid()) + { + char buf[256]; + LOG_INFO << "tell " << reader.tell(); + int nr = reader.read(buf, sizeof buf); + printf("read %d\n", nr); + if (nr >= 0) + { + buf[nr] = '\0'; + printf("data %s", buf); + } + LOG_INFO << "tell " << reader.tell(); + if (strncmp(buf, data, strlen(data)) != 0) + { + printf("failed!!!\n"); + abort(); + } + else + { + printf("PASSED\n"); + } + } + } + + { + muduo::GzipFile writer = muduo::GzipFile::openForWriteExclusive(filename); + if (writer.valid() || errno != EEXIST) + { + printf("FAILED\n"); + } + } +} diff --git a/include/muduo/base/tests/LogFile_test.cc b/include/muduo/base/tests/LogFile_test.cc new file mode 100644 index 0000000..a0b753a --- /dev/null +++ b/include/muduo/base/tests/LogFile_test.cc @@ -0,0 +1,34 @@ +#include "muduo/base/LogFile.h" +#include "muduo/base/Logging.h" + +#include + +std::unique_ptr g_logFile; + +void outputFunc(const char* msg, int len) +{ + g_logFile->append(msg, len); +} + +void flushFunc() +{ + g_logFile->flush(); +} + +int main(int argc, char* argv[]) +{ + char name[256] = { '\0' }; + strncpy(name, argv[0], sizeof name - 1); + g_logFile.reset(new muduo::LogFile(::basename(name), 200*1000)); + muduo::Logger::setOutput(outputFunc); + muduo::Logger::setFlush(flushFunc); + + muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; + + for (int i = 0; i < 10000; ++i) + { + LOG_INFO << line << i; + + usleep(1000); + } +} diff --git a/include/muduo/base/tests/LogStream_bench.cc b/include/muduo/base/tests/LogStream_bench.cc new file mode 100644 index 0000000..c91637a --- /dev/null +++ b/include/muduo/base/tests/LogStream_bench.cc @@ -0,0 +1,82 @@ +#include "muduo/base/LogStream.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +using namespace muduo; + +const size_t N = 1000000; + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +template +void benchPrintf(const char* fmt) +{ + char buf[32]; + Timestamp start(Timestamp::now()); + for (size_t i = 0; i < N; ++i) + snprintf(buf, sizeof buf, fmt, (T)(i)); + Timestamp end(Timestamp::now()); + + printf("benchPrintf %f\n", timeDifference(end, start)); +} + +template +void benchStringStream() +{ + Timestamp start(Timestamp::now()); + std::ostringstream os; + + for (size_t i = 0; i < N; ++i) + { + os << (T)(i); + os.seekp(0, std::ios_base::beg); + } + Timestamp end(Timestamp::now()); + + printf("benchStringStream %f\n", timeDifference(end, start)); +} + +template +void benchLogStream() +{ + Timestamp start(Timestamp::now()); + LogStream os; + for (size_t i = 0; i < N; ++i) + { + os << (T)(i); + os.resetBuffer(); + } + Timestamp end(Timestamp::now()); + + printf("benchLogStream %f\n", timeDifference(end, start)); +} + +int main() +{ + benchPrintf("%d"); + + puts("int"); + benchPrintf("%d"); + benchStringStream(); + benchLogStream(); + + puts("double"); + benchPrintf("%.12g"); + benchStringStream(); + benchLogStream(); + + puts("int64_t"); + benchPrintf("%" PRId64); + benchStringStream(); + benchLogStream(); + + puts("void*"); + benchPrintf("%p"); + benchStringStream(); + benchLogStream(); + +} diff --git a/include/muduo/base/tests/LogStream_test.cc b/include/muduo/base/tests/LogStream_test.cc new file mode 100644 index 0000000..b6070e1 --- /dev/null +++ b/include/muduo/base/tests/LogStream_test.cc @@ -0,0 +1,286 @@ +#include "muduo/base/LogStream.h" + +#include +#include + +//#define BOOST_TEST_MODULE LogStreamTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; + +BOOST_AUTO_TEST_CASE(testLogStreamBooleans) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + BOOST_CHECK_EQUAL(buf.toString(), string("")); + os << true; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os << '\n'; + BOOST_CHECK_EQUAL(buf.toString(), string("1\n")); + os << false; + BOOST_CHECK_EQUAL(buf.toString(), string("1\n0")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamIntegers) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + BOOST_CHECK_EQUAL(buf.toString(), string("")); + os << 1; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os << 0; + BOOST_CHECK_EQUAL(buf.toString(), string("10")); + os << -1; + BOOST_CHECK_EQUAL(buf.toString(), string("10-1")); + os.resetBuffer(); + + os << 0 << " " << 123 << 'x' << 0x64; + BOOST_CHECK_EQUAL(buf.toString(), string("0 123x100")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamIntegerLimits) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + os << -2147483647; + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647")); + os << static_cast(-2147483647 - 1); + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648")); + os << ' '; + os << 2147483647; + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648 2147483647")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-32768")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("32767")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("65535")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483648")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("2147483647")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("4294967295")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-9223372036854775808")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("9223372036854775807")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("18446744073709551615")); + os.resetBuffer(); + + int16_t a = 0; + int32_t b = 0; + int64_t c = 0; + os << a; + os << b; + os << c; + BOOST_CHECK_EQUAL(buf.toString(), string("000")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamFloats) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << 0.0; + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << 1.0; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os.resetBuffer(); + + os << 0.1; + BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); + os.resetBuffer(); + + os << 0.05; + BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); + os.resetBuffer(); + + os << 0.15; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + double a = 0.1; + os << a; + BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); + os.resetBuffer(); + + double b = 0.05; + os << b; + BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); + os.resetBuffer(); + + double c = 0.15; + os << c; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + os << a+b; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + BOOST_CHECK(a+b != c); + + os << 1.23456789; + BOOST_CHECK_EQUAL(buf.toString(), string("1.23456789")); + os.resetBuffer(); + + os << 1.234567; + BOOST_CHECK_EQUAL(buf.toString(), string("1.234567")); + os.resetBuffer(); + + os << -123.456; + BOOST_CHECK_EQUAL(buf.toString(), string("-123.456")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamVoid) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << static_cast(0); + BOOST_CHECK_EQUAL(buf.toString(), string("0x0")); + os.resetBuffer(); + + os << reinterpret_cast(8888); + BOOST_CHECK_EQUAL(buf.toString(), string("0x22B8")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamStrings) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << "Hello "; + BOOST_CHECK_EQUAL(buf.toString(), string("Hello ")); + + string chenshuo = "Shuo Chen"; + os << chenshuo; + BOOST_CHECK_EQUAL(buf.toString(), string("Hello Shuo Chen")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamFmts) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << muduo::Fmt("%4d", 1); + BOOST_CHECK_EQUAL(buf.toString(), string(" 1")); + os.resetBuffer(); + + os << muduo::Fmt("%4.2f", 1.2); + BOOST_CHECK_EQUAL(buf.toString(), string("1.20")); + os.resetBuffer(); + + os << muduo::Fmt("%4.2f", 1.2) << muduo::Fmt("%4d", 43); + BOOST_CHECK_EQUAL(buf.toString(), string("1.20 43")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamLong) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + for (int i = 0; i < 399; ++i) + { + os << "123456789 "; + BOOST_CHECK_EQUAL(buf.length(), 10*(i+1)); + BOOST_CHECK_EQUAL(buf.avail(), 4000 - 10*(i+1)); + } + + os << "abcdefghi "; + BOOST_CHECK_EQUAL(buf.length(), 3990); + BOOST_CHECK_EQUAL(buf.avail(), 10); + + os << "abcdefghi"; + BOOST_CHECK_EQUAL(buf.length(), 3999); + BOOST_CHECK_EQUAL(buf.avail(), 1); +} + +BOOST_AUTO_TEST_CASE(testFormatSI) +{ + BOOST_CHECK_EQUAL(muduo::formatSI(0), string("0")); + BOOST_CHECK_EQUAL(muduo::formatSI(999), string("999")); + BOOST_CHECK_EQUAL(muduo::formatSI(1000), string("1.00k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9990), string("9.99k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9994), string("9.99k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9995), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10000), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10049), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10050), string("10.1k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99900), string("99.9k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99949), string("99.9k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99950), string("100k")); + BOOST_CHECK_EQUAL(muduo::formatSI(100499), string("100k")); + // FIXME: + // BOOST_CHECK_EQUAL(muduo::formatSI(100500), string("101k")); + BOOST_CHECK_EQUAL(muduo::formatSI(100501), string("101k")); + BOOST_CHECK_EQUAL(muduo::formatSI(999499), string("999k")); + BOOST_CHECK_EQUAL(muduo::formatSI(999500), string("1.00M")); + BOOST_CHECK_EQUAL(muduo::formatSI(1004999), string("1.00M")); + // BOOST_CHECK_EQUAL(muduo::formatSI(1005000), string("1.01M")); + BOOST_CHECK_EQUAL(muduo::formatSI(1005001), string("1.01M")); + BOOST_CHECK_EQUAL(muduo::formatSI(INT64_MAX), string("9.22E")); +} + +BOOST_AUTO_TEST_CASE(testFormatIEC) +{ + BOOST_CHECK_EQUAL(muduo::formatIEC(0), string("0")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1023), string("1023")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1024), string("1.00Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10234), string("9.99Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10235), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10240), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10291), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10292), string("10.1Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102348), string("99.9Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102349), string("100Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102912), string("100Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102913), string("101Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1022976), string("999Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1047552), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1047961), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048063), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048064), string("1.00Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048576), string("1.00Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10480517), string("9.99Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10480518), string("10.0Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(INT64_MAX), string("8.00Ei")); +} diff --git a/include/muduo/base/tests/Logging_test.cc b/include/muduo/base/tests/Logging_test.cc new file mode 100644 index 0000000..3de5e86 --- /dev/null +++ b/include/muduo/base/tests/Logging_test.cc @@ -0,0 +1,122 @@ +#include "muduo/base/Logging.h" +#include "muduo/base/LogFile.h" +#include "muduo/base/ThreadPool.h" +#include "muduo/base/TimeZone.h" + +#include +#include + +int g_total; +FILE* g_file; +std::unique_ptr g_logFile; + +void dummyOutput(const char* msg, int len) +{ + g_total += len; + if (g_file) + { + fwrite(msg, 1, len, g_file); + } + else if (g_logFile) + { + g_logFile->append(msg, len); + } +} + +void bench(const char* type) +{ + muduo::Logger::setOutput(dummyOutput); + muduo::Timestamp start(muduo::Timestamp::now()); + g_total = 0; + + int n = 1000*1000; + const bool kLongLog = false; + muduo::string empty = " "; + muduo::string longStr(3000, 'X'); + longStr += " "; + for (int i = 0; i < n; ++i) + { + LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz" + << (kLongLog ? longStr : empty) + << i; + } + muduo::Timestamp end(muduo::Timestamp::now()); + double seconds = timeDifference(end, start); + printf("%12s: %f seconds, %d bytes, %10.2f msg/s, %.2f MiB/s\n", + type, seconds, g_total, n / seconds, g_total / seconds / (1024 * 1024)); +} + +void logInThread() +{ + LOG_INFO << "logInThread"; + usleep(1000); +} + +int main() +{ + getppid(); // for ltrace and strace + + muduo::ThreadPool pool("pool"); + pool.start(5); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + + LOG_TRACE << "trace"; + LOG_DEBUG << "debug"; + LOG_INFO << "Hello"; + LOG_WARN << "World"; + LOG_ERROR << "Error"; + LOG_INFO << sizeof(muduo::Logger); + LOG_INFO << sizeof(muduo::LogStream); + LOG_INFO << sizeof(muduo::Fmt); + LOG_INFO << sizeof(muduo::LogStream::Buffer); + + sleep(1); + bench("nop"); + + char buffer[64*1024]; + + g_file = fopen("/dev/null", "w"); + setbuffer(g_file, buffer, sizeof buffer); + bench("/dev/null"); + fclose(g_file); + + g_file = fopen("/tmp/log", "w"); + setbuffer(g_file, buffer, sizeof buffer); + bench("/tmp/log"); + fclose(g_file); + + g_file = NULL; + g_logFile.reset(new muduo::LogFile("test_log_st", 500*1000*1000, false)); + bench("test_log_st"); + + g_logFile.reset(new muduo::LogFile("test_log_mt", 500*1000*1000, true)); + bench("test_log_mt"); + g_logFile.reset(); + + { + g_file = stdout; + sleep(1); + muduo::TimeZone beijing(8*3600, "CST"); + muduo::Logger::setTimeZone(beijing); + LOG_TRACE << "trace CST"; + LOG_DEBUG << "debug CST"; + LOG_INFO << "Hello CST"; + LOG_WARN << "World CST"; + LOG_ERROR << "Error CST"; + + sleep(1); + muduo::TimeZone newyork("/usr/share/zoneinfo/America/New_York"); + muduo::Logger::setTimeZone(newyork); + LOG_TRACE << "trace NYT"; + LOG_DEBUG << "debug NYT"; + LOG_INFO << "Hello NYT"; + LOG_WARN << "World NYT"; + LOG_ERROR << "Error NYT"; + g_file = NULL; + } + bench("timezone nop"); +} diff --git a/include/muduo/base/tests/Mutex_test.cc b/include/muduo/base/tests/Mutex_test.cc new file mode 100644 index 0000000..0c22d71 --- /dev/null +++ b/include/muduo/base/tests/Mutex_test.cc @@ -0,0 +1,82 @@ +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include + +using namespace muduo; +using namespace std; + +MutexLock g_mutex; +vector g_vec; +const int kCount = 10*1000*1000; + +void threadFunc() +{ + for (int i = 0; i < kCount; ++i) + { + MutexLockGuard lock(g_mutex); + g_vec.push_back(i); + } +} + +int foo() __attribute__ ((noinline)); + +int g_count = 0; +int foo() +{ + MutexLockGuard lock(g_mutex); + if (!g_mutex.isLockedByThisThread()) + { + printf("FAIL\n"); + return -1; + } + + ++g_count; + return 0; +} + +int main() +{ + MCHECK(foo()); + if (g_count != 1) + { + printf("MCHECK calls twice.\n"); + abort(); + } + + const int kMaxThreads = 8; + g_vec.reserve(kMaxThreads * kCount); + + Timestamp start(Timestamp::now()); + for (int i = 0; i < kCount; ++i) + { + g_vec.push_back(i); + } + + printf("single thread without lock %f\n", timeDifference(Timestamp::now(), start)); + + start = Timestamp::now(); + threadFunc(); + printf("single thread with lock %f\n", timeDifference(Timestamp::now(), start)); + + for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads) + { + std::vector> threads; + g_vec.clear(); + start = Timestamp::now(); + for (int i = 0; i < nthreads; ++i) + { + threads.emplace_back(new Thread(&threadFunc)); + threads.back()->start(); + } + for (int i = 0; i < nthreads; ++i) + { + threads[i]->join(); + } + printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start)); + } +} + diff --git a/include/muduo/base/tests/ProcessInfo_test.cc b/include/muduo/base/tests/ProcessInfo_test.cc new file mode 100644 index 0000000..6e30bad --- /dev/null +++ b/include/muduo/base/tests/ProcessInfo_test.cc @@ -0,0 +1,17 @@ +#include "muduo/base/ProcessInfo.h" +#include +#define __STDC_FORMAT_MACROS +#include + +int main() +{ + printf("pid = %d\n", muduo::ProcessInfo::pid()); + printf("uid = %d\n", muduo::ProcessInfo::uid()); + printf("euid = %d\n", muduo::ProcessInfo::euid()); + printf("start time = %s\n", muduo::ProcessInfo::startTime().toFormattedString().c_str()); + printf("hostname = %s\n", muduo::ProcessInfo::hostname().c_str()); + printf("opened files = %d\n", muduo::ProcessInfo::openedFiles()); + printf("threads = %zd\n", muduo::ProcessInfo::threads().size()); + printf("num threads = %d\n", muduo::ProcessInfo::numThreads()); + printf("status = %s\n", muduo::ProcessInfo::procStatus().c_str()); +} diff --git a/include/muduo/base/tests/SingletonThreadLocal_test.cc b/include/muduo/base/tests/SingletonThreadLocal_test.cc new file mode 100644 index 0000000..29edf6c --- /dev/null +++ b/include/muduo/base/tests/SingletonThreadLocal_test.cc @@ -0,0 +1,58 @@ +#include "muduo/base/Singleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/ThreadLocal.h" +#include "muduo/base/Thread.h" + +#include +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +#define STL muduo::Singleton >::instance().value() + +void print() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &STL, + STL.name().c_str()); +} + +void threadFunc(const char* changeTo) +{ + print(); + STL.setName(changeTo); + sleep(1); + print(); +} + +int main() +{ + STL.setName("main one"); + muduo::Thread t1(std::bind(threadFunc, "thread1")); + muduo::Thread t2(std::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + print(); + t2.join(); + pthread_exit(0); +} diff --git a/include/muduo/base/tests/Singleton_test.cc b/include/muduo/base/tests/Singleton_test.cc new file mode 100644 index 0000000..124d7f7 --- /dev/null +++ b/include/muduo/base/tests/Singleton_test.cc @@ -0,0 +1,65 @@ +#include "muduo/base/Singleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +class TestNoDestroy : muduo::noncopyable +{ + public: + // Tag member for Singleton + void no_destroy(); + + TestNoDestroy() + { + printf("tid=%d, constructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); + } + + ~TestNoDestroy() + { + printf("tid=%d, destructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); + } +}; + +void threadFunc() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); + muduo::Singleton::instance().setName("only one, changed"); +} + +int main() +{ + muduo::Singleton::instance().setName("only one"); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); + muduo::Singleton::instance(); + printf("with valgrind, you should see %zd-byte memory leak.\n", sizeof(TestNoDestroy)); +} diff --git a/include/muduo/base/tests/ThreadLocalSingleton_test.cc b/include/muduo/base/tests/ThreadLocalSingleton_test.cc new file mode 100644 index 0000000..efe485a --- /dev/null +++ b/include/muduo/base/tests/ThreadLocalSingleton_test.cc @@ -0,0 +1,58 @@ +#include "muduo/base/ThreadLocalSingleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +void threadFunc(const char* changeTo) +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + muduo::ThreadLocalSingleton::instance().setName(changeTo); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + + // no need to manually delete it + // muduo::ThreadLocalSingleton::destroy(); +} + +int main() +{ + muduo::ThreadLocalSingleton::instance().setName("main one"); + muduo::Thread t1(std::bind(threadFunc, "thread1")); + muduo::Thread t2(std::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + t2.join(); + + pthread_exit(0); +} diff --git a/include/muduo/base/tests/ThreadLocal_test.cc b/include/muduo/base/tests/ThreadLocal_test.cc new file mode 100644 index 0000000..a5b89cf --- /dev/null +++ b/include/muduo/base/tests/ThreadLocal_test.cc @@ -0,0 +1,61 @@ +#include "muduo/base/ThreadLocal.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +muduo::ThreadLocal testObj1; +muduo::ThreadLocal testObj2; + +void print() +{ + printf("tid=%d, obj1 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj1.value(), + testObj1.value().name().c_str()); + printf("tid=%d, obj2 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj2.value(), + testObj2.value().name().c_str()); +} + +void threadFunc() +{ + print(); + testObj1.value().setName("changed 1"); + testObj2.value().setName("changed 42"); + print(); +} + +int main() +{ + testObj1.value().setName("main one"); + print(); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + testObj2.value().setName("main two"); + print(); + + pthread_exit(0); +} diff --git a/include/muduo/base/tests/ThreadPool_test.cc b/include/muduo/base/tests/ThreadPool_test.cc new file mode 100644 index 0000000..de0dd60 --- /dev/null +++ b/include/muduo/base/tests/ThreadPool_test.cc @@ -0,0 +1,97 @@ +#include "muduo/base/ThreadPool.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Logging.h" + +#include +#include // usleep + +void print() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void printString(const std::string& str) +{ + LOG_INFO << str; + usleep(100*1000); +} + +void test(int maxSize) +{ + LOG_WARN << "Test ThreadPool with max queue size = " << maxSize; + muduo::ThreadPool pool("MainThreadPool"); + pool.setMaxQueueSize(maxSize); + pool.start(5); + + LOG_WARN << "Adding"; + pool.run(print); + pool.run(print); + for (int i = 0; i < 100; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "task %d", i); + pool.run(std::bind(printString, std::string(buf))); + } + LOG_WARN << "Done"; + + muduo::CountDownLatch latch(1); + pool.run(std::bind(&muduo::CountDownLatch::countDown, &latch)); + latch.wait(); + pool.stop(); +} + +/* + * Wish we could do this in the future. +void testMove() +{ + muduo::ThreadPool pool; + pool.start(2); + + std::unique_ptr x(new int(42)); + pool.run([y = std::move(x)]{ printf("%d: %d\n", muduo::CurrentThread::tid(), *y); }); + pool.stop(); +} +*/ + +void longTask(int num) +{ + LOG_INFO << "longTask " << num; + muduo::CurrentThread::sleepUsec(3000000); +} + +void test2() +{ + LOG_WARN << "Test ThreadPool by stoping early."; + muduo::ThreadPool pool("ThreadPool"); + pool.setMaxQueueSize(5); + pool.start(3); + + muduo::Thread thread1([&pool]() + { + for (int i = 0; i < 20; ++i) + { + pool.run(std::bind(longTask, i)); + } + }, "thread1"); + thread1.start(); + + muduo::CurrentThread::sleepUsec(5000000); + LOG_WARN << "stop pool"; + pool.stop(); // early stop + + thread1.join(); + // run() after stop() + pool.run(print); + LOG_WARN << "test2 Done"; +} + +int main() +{ + test(0); + test(1); + test(5); + test(10); + test(50); + test2(); +} diff --git a/include/muduo/base/tests/Thread_bench.cc b/include/muduo/base/tests/Thread_bench.cc new file mode 100644 index 0000000..ae3d49c --- /dev/null +++ b/include/muduo/base/tests/Thread_bench.cc @@ -0,0 +1,86 @@ +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include +#include +#include + +muduo::MutexLock g_mutex; +std::map g_delays; + +void threadFunc() +{ + //printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void threadFunc2(muduo::Timestamp start) +{ + muduo::Timestamp now(muduo::Timestamp::now()); + int delay = static_cast(timeDifference(now, start) * 1000000); + muduo::MutexLockGuard lock(g_mutex); + ++g_delays[delay]; +} + +void forkBench() +{ + sleep(10); + muduo::Timestamp start(muduo::Timestamp::now()); + int kProcesses = 10*1000; + + for (int i = 0; i < kProcesses; ++i) + { + pid_t child = fork(); + if (child == 0) + { + exit(0); + } + else + { + waitpid(child, NULL, 0); + } + } + + double timeUsed = timeDifference(muduo::Timestamp::now(), start); + printf("process creation time used %f us\n", timeUsed*1000000/kProcesses); + printf("number of created processes %d\n", kProcesses); +} + +int main(int argc, char* argv[]) +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + muduo::Timestamp start(muduo::Timestamp::now()); + + int kThreads = 100*1000; + for (int i = 0; i < kThreads; ++i) + { + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + } + + double timeUsed = timeDifference(muduo::Timestamp::now(), start); + printf("thread creation time %f us\n", timeUsed*1000000/kThreads); + printf("number of created threads %d\n", muduo::Thread::numCreated()); + + for (int i = 0; i < kThreads; ++i) + { + muduo::Timestamp now(muduo::Timestamp::now()); + muduo::Thread t2(std::bind(threadFunc2, now)); + t2.start(); + t2.join(); + } + { + muduo::MutexLockGuard lock(g_mutex); + for (const auto& delay : g_delays) + { + printf("delay = %d, count = %d\n", + delay.first, delay.second); + } + } + + forkBench(); +} diff --git a/include/muduo/base/tests/Thread_test.cc b/include/muduo/base/tests/Thread_test.cc new file mode 100644 index 0000000..d6e78b9 --- /dev/null +++ b/include/muduo/base/tests/Thread_test.cc @@ -0,0 +1,91 @@ +#include "muduo/base/Thread.h" +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +void mysleep(int seconds) +{ + timespec t = { seconds, 0 }; + nanosleep(&t, NULL); +} + +void threadFunc() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void threadFunc2(int x) +{ + printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x); +} + +void threadFunc3() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); + mysleep(1); +} + +class Foo +{ + public: + explicit Foo(double x) + : x_(x) + { + } + + void memberFunc() + { + printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_); + } + + void memberFunc2(const std::string& text) + { + printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str()); + } + + private: + double x_; +}; + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + + muduo::Thread t1(threadFunc); + t1.start(); + printf("t1.tid=%d\n", t1.tid()); + t1.join(); + + muduo::Thread t2(std::bind(threadFunc2, 42), + "thread for free function with argument"); + t2.start(); + printf("t2.tid=%d\n", t2.tid()); + t2.join(); + + Foo foo(87.53); + muduo::Thread t3(std::bind(&Foo::memberFunc, &foo), + "thread for member function without argument"); + t3.start(); + t3.join(); + + muduo::Thread t4(std::bind(&Foo::memberFunc2, std::ref(foo), std::string("Shuo Chen"))); + t4.start(); + t4.join(); + + { + muduo::Thread t5(threadFunc3); + t5.start(); + // t5 may destruct eariler than thread creation. + } + mysleep(2); + { + muduo::Thread t6(threadFunc3); + t6.start(); + mysleep(2); + // t6 destruct later than thread creation. + } + sleep(2); + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/muduo/base/tests/TimeZone_unittest.cc b/include/muduo/base/tests/TimeZone_unittest.cc new file mode 100644 index 0000000..5d1de82 --- /dev/null +++ b/include/muduo/base/tests/TimeZone_unittest.cc @@ -0,0 +1,276 @@ +#include "muduo/base/TimeZone.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +using muduo::TimeZone; + +struct tm getTm(int year, int month, int day, + int hour, int minute, int seconds) +{ + struct tm gmt; + muduo::memZero(&gmt, sizeof gmt); + gmt.tm_year = year - 1900; + gmt.tm_mon = month - 1; + gmt.tm_mday = day; + gmt.tm_hour = hour; + gmt.tm_min = minute; + gmt.tm_sec = seconds; + return gmt; +} + +struct tm getTm(const char* str) +{ + struct tm gmt; + muduo::memZero(&gmt, sizeof gmt); + strptime(str, "%F %T", &gmt); + return gmt; +} + +time_t getGmt(int year, int month, int day, + int hour, int minute, int seconds) +{ + struct tm gmt = getTm(year, month, day, hour, minute, seconds); + return timegm(&gmt); +} + +time_t getGmt(const char* str) +{ + struct tm gmt = getTm(str); + return timegm(&gmt); +} + +struct TestCase +{ + const char* gmt; + const char* local; + bool isdst; +}; + +void test(const TimeZone& tz, TestCase tc) +{ + time_t gmt = getGmt(tc.gmt); + + { + struct tm local = tz.toLocalTime(gmt); + char buf[256]; + strftime(buf, sizeof buf, "%F %T%z(%Z)", &local); + + if (strcmp(buf, tc.local) != 0 || tc.isdst != local.tm_isdst) + { + printf("WRONG: "); + } + printf("%s -> %s\n", tc.gmt, buf); + } + + { + struct tm local = getTm(tc.local); + local.tm_isdst = tc.isdst; + time_t result = tz.fromLocalTime(local); + if (result != gmt) + { + struct tm local2 = tz.toLocalTime(result); + char buf[256]; + strftime(buf, sizeof buf, "%F %T%z(%Z)", &local2); + + printf("WRONG fromLocalTime: %ld %ld %s\n", + static_cast(gmt), static_cast(result), buf); + } + } +} + +void testNewYork() +{ + TimeZone tz("/usr/share/zoneinfo/America/New_York"); + TestCase cases[] = + { + + { "2006-03-07 00:00:00", "2006-03-06 19:00:00-0500(EST)", false }, + { "2006-04-02 06:59:59", "2006-04-02 01:59:59-0500(EST)", false }, + { "2006-04-02 07:00:00", "2006-04-02 03:00:00-0400(EDT)", true }, + { "2006-05-01 00:00:00", "2006-04-30 20:00:00-0400(EDT)", true }, + { "2006-05-02 01:00:00", "2006-05-01 21:00:00-0400(EDT)", true }, + { "2006-10-21 05:00:00", "2006-10-21 01:00:00-0400(EDT)", true }, + { "2006-10-29 05:59:59", "2006-10-29 01:59:59-0400(EDT)", true }, + { "2006-10-29 06:00:00", "2006-10-29 01:00:00-0500(EST)", false }, + { "2006-10-29 06:59:59", "2006-10-29 01:59:59-0500(EST)", false }, + { "2006-12-31 06:00:00", "2006-12-31 01:00:00-0500(EST)", false }, + { "2007-01-01 00:00:00", "2006-12-31 19:00:00-0500(EST)", false }, + + { "2007-03-07 00:00:00", "2007-03-06 19:00:00-0500(EST)", false }, + { "2007-03-11 06:59:59", "2007-03-11 01:59:59-0500(EST)", false }, + { "2007-03-11 07:00:00", "2007-03-11 03:00:00-0400(EDT)", true }, + { "2007-05-01 00:00:00", "2007-04-30 20:00:00-0400(EDT)", true }, + { "2007-05-02 01:00:00", "2007-05-01 21:00:00-0400(EDT)", true }, + { "2007-10-31 05:00:00", "2007-10-31 01:00:00-0400(EDT)", true }, + { "2007-11-04 05:59:59", "2007-11-04 01:59:59-0400(EDT)", true }, + { "2007-11-04 06:00:00", "2007-11-04 01:00:00-0500(EST)", false }, + { "2007-11-04 06:59:59", "2007-11-04 01:59:59-0500(EST)", false }, + { "2007-12-31 06:00:00", "2007-12-31 01:00:00-0500(EST)", false }, + { "2008-01-01 00:00:00", "2007-12-31 19:00:00-0500(EST)", false }, + + { "2009-03-07 00:00:00", "2009-03-06 19:00:00-0500(EST)", false }, + { "2009-03-08 06:59:59", "2009-03-08 01:59:59-0500(EST)", false }, + { "2009-03-08 07:00:00", "2009-03-08 03:00:00-0400(EDT)", true }, + { "2009-05-01 00:00:00", "2009-04-30 20:00:00-0400(EDT)", true }, + { "2009-05-02 01:00:00", "2009-05-01 21:00:00-0400(EDT)", true }, + { "2009-10-31 05:00:00", "2009-10-31 01:00:00-0400(EDT)", true }, + { "2009-11-01 05:59:59", "2009-11-01 01:59:59-0400(EDT)", true }, + { "2009-11-01 06:00:00", "2009-11-01 01:00:00-0500(EST)", false }, + { "2009-11-01 06:59:59", "2009-11-01 01:59:59-0500(EST)", false }, + { "2009-12-31 06:00:00", "2009-12-31 01:00:00-0500(EST)", false }, + { "2010-01-01 00:00:00", "2009-12-31 19:00:00-0500(EST)", false }, + + { "2010-03-13 00:00:00", "2010-03-12 19:00:00-0500(EST)", false }, + { "2010-03-14 06:59:59", "2010-03-14 01:59:59-0500(EST)", false }, + { "2010-03-14 07:00:00", "2010-03-14 03:00:00-0400(EDT)", true }, + { "2010-05-01 00:00:00", "2010-04-30 20:00:00-0400(EDT)", true }, + { "2010-05-02 01:00:00", "2010-05-01 21:00:00-0400(EDT)", true }, + { "2010-11-06 05:00:00", "2010-11-06 01:00:00-0400(EDT)", true }, + { "2010-11-07 05:59:59", "2010-11-07 01:59:59-0400(EDT)", true }, + { "2010-11-07 06:00:00", "2010-11-07 01:00:00-0500(EST)", false }, + { "2010-11-07 06:59:59", "2010-11-07 01:59:59-0500(EST)", false }, + { "2010-12-31 06:00:00", "2010-12-31 01:00:00-0500(EST)", false }, + { "2011-01-01 00:00:00", "2010-12-31 19:00:00-0500(EST)", false }, + + { "2011-03-01 00:00:00", "2011-02-28 19:00:00-0500(EST)", false }, + { "2011-03-13 06:59:59", "2011-03-13 01:59:59-0500(EST)", false }, + { "2011-03-13 07:00:00", "2011-03-13 03:00:00-0400(EDT)", true }, + { "2011-05-01 00:00:00", "2011-04-30 20:00:00-0400(EDT)", true }, + { "2011-05-02 01:00:00", "2011-05-01 21:00:00-0400(EDT)", true }, + { "2011-11-06 05:59:59", "2011-11-06 01:59:59-0400(EDT)", true }, + { "2011-11-06 06:00:00", "2011-11-06 01:00:00-0500(EST)", false }, + { "2011-11-06 06:59:59", "2011-11-06 01:59:59-0500(EST)", false }, + { "2011-12-31 06:00:00", "2011-12-31 01:00:00-0500(EST)", false }, + { "2012-01-01 00:00:00", "2011-12-31 19:00:00-0500(EST)", false }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testLondon() +{ + TimeZone tz("/usr/share/zoneinfo/Europe/London"); + TestCase cases[] = + { + + { "2011-03-26 00:00:00", "2011-03-26 00:00:00+0000(GMT)", false }, + { "2011-03-27 00:59:59", "2011-03-27 00:59:59+0000(GMT)", false }, + { "2011-03-27 01:00:00", "2011-03-27 02:00:00+0100(BST)", true }, + { "2011-10-30 00:59:59", "2011-10-30 01:59:59+0100(BST)", true }, + { "2011-10-30 01:00:00", "2011-10-30 01:00:00+0000(GMT)", false }, + { "2012-10-30 01:59:59", "2012-10-30 01:59:59+0000(GMT)", false }, + { "2011-12-31 22:00:00", "2011-12-31 22:00:00+0000(GMT)", false }, + { "2012-01-01 00:00:00", "2012-01-01 00:00:00+0000(GMT)", false }, + + { "2012-03-24 00:00:00", "2012-03-24 00:00:00+0000(GMT)", false }, + { "2012-03-25 00:59:59", "2012-03-25 00:59:59+0000(GMT)", false }, + { "2012-03-25 01:00:00", "2012-03-25 02:00:00+0100(BST)", true }, + { "2012-10-28 00:59:59", "2012-10-28 01:59:59+0100(BST)", true }, + { "2012-10-28 01:00:00", "2012-10-28 01:00:00+0000(GMT)", false }, + { "2012-10-28 01:59:59", "2012-10-28 01:59:59+0000(GMT)", false }, + { "2012-12-31 22:00:00", "2012-12-31 22:00:00+0000(GMT)", false }, + { "2013-01-01 00:00:00", "2013-01-01 00:00:00+0000(GMT)", false }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testHongKong() +{ + TimeZone tz("/usr/share/zoneinfo/Asia/Hong_Kong"); + TestCase cases[] = + { + + { "2011-04-03 00:00:00", "2011-04-03 08:00:00+0800(HKT)", false}, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testSydney() +{ + TimeZone tz("/usr/share/zoneinfo/Australia/Sydney"); + TestCase cases[] = + { + + { "2011-01-01 00:00:00", "2011-01-01 11:00:00+1100(EST)", true }, + { "2011-04-02 15:59:59", "2011-04-03 02:59:59+1100(EST)", true }, + { "2011-04-02 16:00:00", "2011-04-03 02:00:00+1000(EST)", false }, + { "2011-04-02 16:59:59", "2011-04-03 02:59:59+1000(EST)", false }, + { "2011-05-02 01:00:00", "2011-05-02 11:00:00+1000(EST)", false }, + { "2011-10-01 15:59:59", "2011-10-02 01:59:59+1000(EST)", false }, + { "2011-10-01 16:00:00", "2011-10-02 03:00:00+1100(EST)", true }, + { "2011-12-31 22:00:00", "2012-01-01 09:00:00+1100(EST)", true }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testUtc() +{ + const int kRange = 100*1000*1000; + for (time_t t = -kRange; t <= kRange; t += 11) + { + struct tm* t1 = gmtime(&t); + struct tm t2 = TimeZone::toUtcTime(t, true); + char buf1[80], buf2[80]; + strftime(buf1, sizeof buf1, "%F %T %u %j", t1); + strftime(buf2, sizeof buf2, "%F %T %u %j", &t2); + if (strcmp(buf1, buf2) != 0) + { + printf("'%s' != '%s'\n", buf1, buf2); + assert(0); + } + time_t t3 = TimeZone::fromUtcTime(t2); + if (t != t3) + { + printf("%ld != %ld\n", static_cast(t), static_cast(t3)); + assert(0); + } + } +} + +void testFixedTimezone() +{ + TimeZone tz(8*3600, "CST"); + TestCase cases[] = + { + + { "2014-04-03 00:00:00", "2014-04-03 08:00:00+0800(CST)", false}, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +int main() +{ + testNewYork(); + testLondon(); + testSydney(); + testHongKong(); + testFixedTimezone(); + testUtc(); +} diff --git a/include/muduo/base/tests/Timestamp_unittest.cc b/include/muduo/base/tests/Timestamp_unittest.cc new file mode 100644 index 0000000..5e27592 --- /dev/null +++ b/include/muduo/base/tests/Timestamp_unittest.cc @@ -0,0 +1,66 @@ +#include "muduo/base/Timestamp.h" +#include +#include + +using muduo::Timestamp; + +void passByConstReference(const Timestamp& x) +{ + printf("%s\n", x.toString().c_str()); +} + +void passByValue(Timestamp x) +{ + printf("%s\n", x.toString().c_str()); +} + +void benchmark() +{ + const int kNumber = 1000*1000; + + std::vector stamps; + stamps.reserve(kNumber); + for (int i = 0; i < kNumber; ++i) + { + stamps.push_back(Timestamp::now()); + } + printf("%s\n", stamps.front().toString().c_str()); + printf("%s\n", stamps.back().toString().c_str()); + printf("%f\n", timeDifference(stamps.back(), stamps.front())); + + int increments[100] = { 0 }; + int64_t start = stamps.front().microSecondsSinceEpoch(); + for (int i = 1; i < kNumber; ++i) + { + int64_t next = stamps[i].microSecondsSinceEpoch(); + int64_t inc = next - start; + start = next; + if (inc < 0) + { + printf("reverse!\n"); + } + else if (inc < 100) + { + ++increments[inc]; + } + else + { + printf("big gap %d\n", static_cast(inc)); + } + } + + for (int i = 0; i < 100; ++i) + { + printf("%2d: %d\n", i, increments[i]); + } +} + +int main() +{ + Timestamp now(Timestamp::now()); + printf("%s\n", now.toString().c_str()); + passByValue(now); + passByConstReference(now); + benchmark(); +} + diff --git a/include/muduo/net/Acceptor.cc b/include/muduo/net/Acceptor.cc new file mode 100644 index 0000000..39d0cb6 --- /dev/null +++ b/include/muduo/net/Acceptor.cc @@ -0,0 +1,89 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Acceptor.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/SocketsOps.h" + +#include +#include +//#include +//#include +#include + +using namespace muduo; +using namespace muduo::net; + +Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) + : loop_(loop), + acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), + acceptChannel_(loop, acceptSocket_.fd()), + listening_(false), + idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) +{ + assert(idleFd_ >= 0); + acceptSocket_.setReuseAddr(true); + acceptSocket_.setReusePort(reuseport); + acceptSocket_.bindAddress(listenAddr); + acceptChannel_.setReadCallback( + std::bind(&Acceptor::handleRead, this)); +} + +Acceptor::~Acceptor() +{ + acceptChannel_.disableAll(); + acceptChannel_.remove(); + ::close(idleFd_); +} + +void Acceptor::listen() +{ + loop_->assertInLoopThread(); + listening_ = true; + acceptSocket_.listen(); + acceptChannel_.enableReading(); +} + +void Acceptor::handleRead() +{ + loop_->assertInLoopThread(); + InetAddress peerAddr; + //FIXME loop until no more + int connfd = acceptSocket_.accept(&peerAddr); + if (connfd >= 0) + { + // string hostport = peerAddr.toIpPort(); + // LOG_TRACE << "Accepts of " << hostport; + if (newConnectionCallback_) + { + newConnectionCallback_(connfd, peerAddr); + } + else + { + sockets::close(connfd); + } + } + else + { + LOG_SYSERR << "in Acceptor::handleRead"; + // Read the section named "The special problem of + // accept()ing when you can't" in libev's doc. + // By Marc Lehmann, author of libev. + if (errno == EMFILE) + { + ::close(idleFd_); + idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); + ::close(idleFd_); + idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); + } + } +} + diff --git a/include/muduo/net/Acceptor.h b/include/muduo/net/Acceptor.h new file mode 100644 index 0000000..761d073 --- /dev/null +++ b/include/muduo/net/Acceptor.h @@ -0,0 +1,63 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_ACCEPTOR_H +#define MUDUO_NET_ACCEPTOR_H + +#include + +#include "muduo/net/Channel.h" +#include "muduo/net/Socket.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; +class InetAddress; + +/// +/// Acceptor of incoming TCP connections. +/// +class Acceptor : noncopyable +{ + public: + typedef std::function NewConnectionCallback; + + Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); + ~Acceptor(); + + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + + void listen(); + + bool listening() const { return listening_; } + + // Deprecated, use the correct spelling one above. + // Leave the wrong spelling here in case one needs to grep it for error messages. + // bool listenning() const { return listening(); } + + private: + void handleRead(); + + EventLoop* loop_; + Socket acceptSocket_; + Channel acceptChannel_; + NewConnectionCallback newConnectionCallback_; + bool listening_; + int idleFd_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_ACCEPTOR_H diff --git a/include/muduo/net/BUILD.bazel b/include/muduo/net/BUILD.bazel new file mode 100644 index 0000000..33d78d1 --- /dev/null +++ b/include/muduo/net/BUILD.bazel @@ -0,0 +1,51 @@ +cc_library( + name = "net", + srcs = [ + "Acceptor.cc", + "Buffer.cc", + "Channel.cc", + "Connector.cc", + "EventLoop.cc", + "EventLoopThread.cc", + "EventLoopThreadPool.cc", + "InetAddress.cc", + "Poller.cc", + "Socket.cc", + "SocketsOps.cc", + "TcpClient.cc", + "TcpConnection.cc", + "TcpServer.cc", + "Timer.cc", + "TimerQueue.cc", + "poller/DefaultPoller.cc", + "poller/EPollPoller.cc", + "poller/PollPoller.cc", + ], + hdrs = [ + "Acceptor.h", + "Buffer.h", + "Callbacks.h", + "Channel.h", + "Connector.h", + "Endian.h", + "EventLoop.h", + "EventLoopThread.h", + "EventLoopThreadPool.h", + "InetAddress.h", + "Poller.h", + "Socket.h", + "SocketsOps.h", + "TcpClient.h", + "TcpConnection.h", + "TcpServer.h", + "Timer.h", + "TimerId.h", + "TimerQueue.h", + "poller/EPollPoller.h", + "poller/PollPoller.h", + ], + visibility = ["//visibility:public"], + deps = [ + "//muduo/base", + ], +) diff --git a/include/muduo/net/Buffer.cc b/include/muduo/net/Buffer.cc new file mode 100644 index 0000000..7c921fc --- /dev/null +++ b/include/muduo/net/Buffer.cc @@ -0,0 +1,58 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Buffer.h" + +#include "muduo/net/SocketsOps.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +const char Buffer::kCRLF[] = "\r\n"; + +const size_t Buffer::kCheapPrepend; +const size_t Buffer::kInitialSize; + +ssize_t Buffer::readFd(int fd, int* savedErrno) +{ + // saved an ioctl()/FIONREAD call to tell how much to read + char extrabuf[65536]; + struct iovec vec[2]; + const size_t writable = writableBytes(); + vec[0].iov_base = begin()+writerIndex_; + vec[0].iov_len = writable; + vec[1].iov_base = extrabuf; + vec[1].iov_len = sizeof extrabuf; + // when there is enough space in this buffer, don't read into extrabuf. + // when extrabuf is used, we read 128k-1 bytes at most. + const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; + const ssize_t n = sockets::readv(fd, vec, iovcnt); + if (n < 0) + { + *savedErrno = errno; + } + else if (implicit_cast(n) <= writable) + { + writerIndex_ += n; + } + else + { + writerIndex_ = buffer_.size(); + append(extrabuf, n - writable); + } + // if (n == writable + sizeof extrabuf) + // { + // goto line_30; + // } + return n; +} + diff --git a/include/muduo/net/Buffer.h b/include/muduo/net/Buffer.h new file mode 100644 index 0000000..4fa82d4 --- /dev/null +++ b/include/muduo/net/Buffer.h @@ -0,0 +1,422 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_BUFFER_H +#define MUDUO_NET_BUFFER_H + +#include "muduo/base/copyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" + +#include "muduo/net/Endian.h" + +#include +#include + +#include +#include +//#include // ssize_t + +namespace muduo +{ +namespace net +{ + +/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer +/// +/// @code +/// +-------------------+------------------+------------------+ +/// | prependable bytes | readable bytes | writable bytes | +/// | | (CONTENT) | | +/// +-------------------+------------------+------------------+ +/// | | | | +/// 0 <= readerIndex <= writerIndex <= size +/// @endcode +class Buffer : public muduo::copyable +{ + public: + static const size_t kCheapPrepend = 8; + static const size_t kInitialSize = 1024; + + explicit Buffer(size_t initialSize = kInitialSize) + : buffer_(kCheapPrepend + initialSize), + readerIndex_(kCheapPrepend), + writerIndex_(kCheapPrepend) + { + assert(readableBytes() == 0); + assert(writableBytes() == initialSize); + assert(prependableBytes() == kCheapPrepend); + } + + // implicit copy-ctor, move-ctor, dtor and assignment are fine + // NOTE: implicit move-ctor is added in g++ 4.6 + + void swap(Buffer& rhs) + { + buffer_.swap(rhs.buffer_); + std::swap(readerIndex_, rhs.readerIndex_); + std::swap(writerIndex_, rhs.writerIndex_); + } + + size_t readableBytes() const + { return writerIndex_ - readerIndex_; } + + size_t writableBytes() const + { return buffer_.size() - writerIndex_; } + + size_t prependableBytes() const + { return readerIndex_; } + + const char* peek() const + { return begin() + readerIndex_; } + + const char* findCRLF() const + { + // FIXME: replace with memmem()? + const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; + } + + const char* findCRLF(const char* start) const + { + assert(peek() <= start); + assert(start <= beginWrite()); + // FIXME: replace with memmem()? + const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; + } + + const char* findEOL() const + { + const void* eol = memchr(peek(), '\n', readableBytes()); + return static_cast(eol); + } + + const char* findEOL(const char* start) const + { + assert(peek() <= start); + assert(start <= beginWrite()); + const void* eol = memchr(start, '\n', beginWrite() - start); + return static_cast(eol); + } + + // retrieve returns void, to prevent + // string str(retrieve(readableBytes()), readableBytes()); + // the evaluation of two functions are unspecified + void retrieve(size_t len) + { + assert(len <= readableBytes()); + if (len < readableBytes()) + { + readerIndex_ += len; + } + else + { + retrieveAll(); + } + } + + void retrieveUntil(const char* end) + { + assert(peek() <= end); + assert(end <= beginWrite()); + retrieve(end - peek()); + } + + void retrieveInt64() + { + retrieve(sizeof(int64_t)); + } + + void retrieveInt32() + { + retrieve(sizeof(int32_t)); + } + + void retrieveInt16() + { + retrieve(sizeof(int16_t)); + } + + void retrieveInt8() + { + retrieve(sizeof(int8_t)); + } + + void retrieveAll() + { + readerIndex_ = kCheapPrepend; + writerIndex_ = kCheapPrepend; + } + + string retrieveAllAsString() + { + return retrieveAsString(readableBytes()); + } + + string retrieveAsString(size_t len) + { + assert(len <= readableBytes()); + string result(peek(), len); + retrieve(len); + return result; + } + + StringPiece toStringPiece() const + { + return StringPiece(peek(), static_cast(readableBytes())); + } + + void append(const StringPiece& str) + { + append(str.data(), str.size()); + } + + void append(const char* /*restrict*/ data, size_t len) + { + ensureWritableBytes(len); + std::copy(data, data+len, beginWrite()); + hasWritten(len); + } + + void append(const void* /*restrict*/ data, size_t len) + { + append(static_cast(data), len); + } + + void ensureWritableBytes(size_t len) + { + if (writableBytes() < len) + { + makeSpace(len); + } + assert(writableBytes() >= len); + } + + char* beginWrite() + { return begin() + writerIndex_; } + + const char* beginWrite() const + { return begin() + writerIndex_; } + + void hasWritten(size_t len) + { + assert(len <= writableBytes()); + writerIndex_ += len; + } + + void unwrite(size_t len) + { + assert(len <= readableBytes()); + writerIndex_ -= len; + } + + /// + /// Append int64_t using network endian + /// + void appendInt64(int64_t x) + { + int64_t be64 = sockets::hostToNetwork64(x); + append(&be64, sizeof be64); + } + + /// + /// Append int32_t using network endian + /// + void appendInt32(int32_t x) + { + int32_t be32 = sockets::hostToNetwork32(x); + append(&be32, sizeof be32); + } + + void appendInt16(int16_t x) + { + int16_t be16 = sockets::hostToNetwork16(x); + append(&be16, sizeof be16); + } + + void appendInt8(int8_t x) + { + append(&x, sizeof x); + } + + /// + /// Read int64_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int64_t readInt64() + { + int64_t result = peekInt64(); + retrieveInt64(); + return result; + } + + /// + /// Read int32_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int32_t readInt32() + { + int32_t result = peekInt32(); + retrieveInt32(); + return result; + } + + int16_t readInt16() + { + int16_t result = peekInt16(); + retrieveInt16(); + return result; + } + + int8_t readInt8() + { + int8_t result = peekInt8(); + retrieveInt8(); + return result; + } + + /// + /// Peek int64_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int64_t) + int64_t peekInt64() const + { + assert(readableBytes() >= sizeof(int64_t)); + int64_t be64 = 0; + ::memcpy(&be64, peek(), sizeof be64); + return sockets::networkToHost64(be64); + } + + /// + /// Peek int32_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int32_t peekInt32() const + { + assert(readableBytes() >= sizeof(int32_t)); + int32_t be32 = 0; + ::memcpy(&be32, peek(), sizeof be32); + return sockets::networkToHost32(be32); + } + + int16_t peekInt16() const + { + assert(readableBytes() >= sizeof(int16_t)); + int16_t be16 = 0; + ::memcpy(&be16, peek(), sizeof be16); + return sockets::networkToHost16(be16); + } + + int8_t peekInt8() const + { + assert(readableBytes() >= sizeof(int8_t)); + int8_t x = *peek(); + return x; + } + + /// + /// Prepend int64_t using network endian + /// + void prependInt64(int64_t x) + { + int64_t be64 = sockets::hostToNetwork64(x); + prepend(&be64, sizeof be64); + } + + /// + /// Prepend int32_t using network endian + /// + void prependInt32(int32_t x) + { + int32_t be32 = sockets::hostToNetwork32(x); + prepend(&be32, sizeof be32); + } + + void prependInt16(int16_t x) + { + int16_t be16 = sockets::hostToNetwork16(x); + prepend(&be16, sizeof be16); + } + + void prependInt8(int8_t x) + { + prepend(&x, sizeof x); + } + + void prepend(const void* /*restrict*/ data, size_t len) + { + assert(len <= prependableBytes()); + readerIndex_ -= len; + const char* d = static_cast(data); + std::copy(d, d+len, begin()+readerIndex_); + } + + void shrink(size_t reserve) + { + // FIXME: use vector::shrink_to_fit() in C++ 11 if possible. + Buffer other; + other.ensureWritableBytes(readableBytes()+reserve); + other.append(toStringPiece()); + swap(other); + } + + size_t internalCapacity() const + { + return buffer_.capacity(); + } + + /// Read data directly into buffer. + /// + /// It may implement with readv(2) + /// @return result of read(2), @c errno is saved + ssize_t readFd(int fd, int* savedErrno); + + private: + + char* begin() + { return &*buffer_.begin(); } + + const char* begin() const + { return &*buffer_.begin(); } + + void makeSpace(size_t len) + { + if (writableBytes() + prependableBytes() < len + kCheapPrepend) + { + // FIXME: move readable data + buffer_.resize(writerIndex_+len); + } + else + { + // move readable data to the front, make space inside buffer + assert(kCheapPrepend < readerIndex_); + size_t readable = readableBytes(); + std::copy(begin()+readerIndex_, + begin()+writerIndex_, + begin()+kCheapPrepend); + readerIndex_ = kCheapPrepend; + writerIndex_ = readerIndex_ + readable; + assert(readable == readableBytes()); + } + } + + private: + std::vector buffer_; + size_t readerIndex_; + size_t writerIndex_; + + static const char kCRLF[]; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_BUFFER_H diff --git a/include/muduo/net/CMakeLists.txt b/include/muduo/net/CMakeLists.txt new file mode 100644 index 0000000..7510d87 --- /dev/null +++ b/include/muduo/net/CMakeLists.txt @@ -0,0 +1,69 @@ +include(CheckFunctionExists) + +check_function_exists(accept4 HAVE_ACCEPT4) +if(NOT HAVE_ACCEPT4) + set_source_files_properties(SocketsOps.cc PROPERTIES COMPILE_FLAGS "-DNO_ACCEPT4") +endif() + +set(net_SRCS + Acceptor.cc + Buffer.cc + Channel.cc + Connector.cc + EventLoop.cc + EventLoopThread.cc + EventLoopThreadPool.cc + InetAddress.cc + Poller.cc + poller/DefaultPoller.cc + poller/EPollPoller.cc + poller/PollPoller.cc + Socket.cc + SocketsOps.cc + TcpClient.cc + TcpConnection.cc + TcpServer.cc + Timer.cc + TimerQueue.cc + ) + +add_library(muduo_net ${net_SRCS}) +target_link_libraries(muduo_net muduo_base) + +#add_library(muduo_net_cpp11 ${net_SRCS}) +#target_link_libraries(muduo_net_cpp11 muduo_base_cpp11) +#set_target_properties(muduo_net_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") + +install(TARGETS muduo_net DESTINATION lib) +#install(TARGETS muduo_net_cpp11 DESTINATION lib) + +set(HEADERS + Buffer.h + Callbacks.h + Channel.h + Endian.h + EventLoop.h + EventLoopThread.h + EventLoopThreadPool.h + InetAddress.h + TcpClient.h + TcpConnection.h + TcpServer.h + TimerId.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net) + +add_subdirectory(http) +add_subdirectory(inspect) + +if(MUDUO_BUILD_EXAMPLES) + add_subdirectory(tests) +endif() + +if(PROTOBUF_FOUND) + add_subdirectory(protobuf) + add_subdirectory(protorpc) +else() + add_subdirectory(protobuf EXCLUDE_FROM_ALL) + add_subdirectory(protorpc EXCLUDE_FROM_ALL) +endif() diff --git a/include/muduo/net/Callbacks.h b/include/muduo/net/Callbacks.h new file mode 100644 index 0000000..443ed79 --- /dev/null +++ b/include/muduo/net/Callbacks.h @@ -0,0 +1,82 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_CALLBACKS_H +#define MUDUO_NET_CALLBACKS_H + +#include "muduo/base/Timestamp.h" + +#include +#include + +namespace muduo +{ + +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; + +// should really belong to base/Types.h, but is not included there. + +template +inline T* get_pointer(const std::shared_ptr& ptr) +{ + return ptr.get(); +} + +template +inline T* get_pointer(const std::unique_ptr& ptr) +{ + return ptr.get(); +} + +// Adapted from google-protobuf stubs/common.h +// see License in muduo/base/Types.h +template +inline ::std::shared_ptr down_pointer_cast(const ::std::shared_ptr& f) { + if (false) + { + implicit_cast(0); + } + +#ifndef NDEBUG + assert(f == NULL || dynamic_cast(get_pointer(f)) != NULL); +#endif + return ::std::static_pointer_cast(f); +} + +namespace net +{ + +// All client visible callbacks go here. + +class Buffer; +class TcpConnection; +typedef std::shared_ptr TcpConnectionPtr; +typedef std::function TimerCallback; +typedef std::function ConnectionCallback; +typedef std::function CloseCallback; +typedef std::function WriteCompleteCallback; +typedef std::function HighWaterMarkCallback; + +// the data has been read to (buf, len) +typedef std::function MessageCallback; + +void defaultConnectionCallback(const TcpConnectionPtr& conn); +void defaultMessageCallback(const TcpConnectionPtr& conn, + Buffer* buffer, + Timestamp receiveTime); + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CALLBACKS_H diff --git a/include/muduo/net/Channel.cc b/include/muduo/net/Channel.cc new file mode 100644 index 0000000..1e9a40a --- /dev/null +++ b/include/muduo/net/Channel.cc @@ -0,0 +1,146 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +const int Channel::kNoneEvent = 0; +const int Channel::kReadEvent = POLLIN | POLLPRI; +const int Channel::kWriteEvent = POLLOUT; + +Channel::Channel(EventLoop* loop, int fd__) + : loop_(loop), + fd_(fd__), + events_(0), + revents_(0), + index_(-1), + logHup_(true), + tied_(false), + eventHandling_(false), + addedToLoop_(false) +{ +} + +Channel::~Channel() +{ + assert(!eventHandling_); + assert(!addedToLoop_); + if (loop_->isInLoopThread()) + { + assert(!loop_->hasChannel(this)); + } +} + +void Channel::tie(const std::shared_ptr& obj) +{ + tie_ = obj; + tied_ = true; +} + +void Channel::update() +{ + addedToLoop_ = true; + loop_->updateChannel(this); +} + +void Channel::remove() +{ + assert(isNoneEvent()); + addedToLoop_ = false; + loop_->removeChannel(this); +} + +void Channel::handleEvent(Timestamp receiveTime) +{ + std::shared_ptr guard; + if (tied_) + { + guard = tie_.lock(); + if (guard) + { + handleEventWithGuard(receiveTime); + } + } + else + { + handleEventWithGuard(receiveTime); + } +} + +void Channel::handleEventWithGuard(Timestamp receiveTime) +{ + eventHandling_ = true; + LOG_TRACE << reventsToString(); + if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) + { + if (logHup_) + { + LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP"; + } + if (closeCallback_) closeCallback_(); + } + + if (revents_ & POLLNVAL) + { + LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL"; + } + + if (revents_ & (POLLERR | POLLNVAL)) + { + if (errorCallback_) errorCallback_(); + } + if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) + { + if (readCallback_) readCallback_(receiveTime); + } + if (revents_ & POLLOUT) + { + if (writeCallback_) writeCallback_(); + } + eventHandling_ = false; +} + +string Channel::reventsToString() const +{ + return eventsToString(fd_, revents_); +} + +string Channel::eventsToString() const +{ + return eventsToString(fd_, events_); +} + +string Channel::eventsToString(int fd, int ev) +{ + std::ostringstream oss; + oss << fd << ": "; + if (ev & POLLIN) + oss << "IN "; + if (ev & POLLPRI) + oss << "PRI "; + if (ev & POLLOUT) + oss << "OUT "; + if (ev & POLLHUP) + oss << "HUP "; + if (ev & POLLRDHUP) + oss << "RDHUP "; + if (ev & POLLERR) + oss << "ERR "; + if (ev & POLLNVAL) + oss << "NVAL "; + + return oss.str(); +} diff --git a/include/muduo/net/Channel.h b/include/muduo/net/Channel.h new file mode 100644 index 0000000..bafa224 --- /dev/null +++ b/include/muduo/net/Channel.h @@ -0,0 +1,113 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_CHANNEL_H +#define MUDUO_NET_CHANNEL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/Timestamp.h" + +#include +#include + +namespace muduo +{ +namespace net +{ + +class EventLoop; + +/// +/// A selectable I/O channel. +/// +/// This class doesn't own the file descriptor. +/// The file descriptor could be a socket, +/// an eventfd, a timerfd, or a signalfd +class Channel : noncopyable +{ + public: + typedef std::function EventCallback; + typedef std::function ReadEventCallback; + + Channel(EventLoop* loop, int fd); + ~Channel(); + + void handleEvent(Timestamp receiveTime); + void setReadCallback(ReadEventCallback cb) + { readCallback_ = std::move(cb); } + void setWriteCallback(EventCallback cb) + { writeCallback_ = std::move(cb); } + void setCloseCallback(EventCallback cb) + { closeCallback_ = std::move(cb); } + void setErrorCallback(EventCallback cb) + { errorCallback_ = std::move(cb); } + + /// Tie this channel to the owner object managed by shared_ptr, + /// prevent the owner object being destroyed in handleEvent. + void tie(const std::shared_ptr&); + + int fd() const { return fd_; } + int events() const { return events_; } + void set_revents(int revt) { revents_ = revt; } // used by pollers + // int revents() const { return revents_; } + bool isNoneEvent() const { return events_ == kNoneEvent; } + + void enableReading() { events_ |= kReadEvent; update(); } + void disableReading() { events_ &= ~kReadEvent; update(); } + void enableWriting() { events_ |= kWriteEvent; update(); } + void disableWriting() { events_ &= ~kWriteEvent; update(); } + void disableAll() { events_ = kNoneEvent; update(); } + bool isWriting() const { return events_ & kWriteEvent; } + bool isReading() const { return events_ & kReadEvent; } + + // for Poller + int index() { return index_; } + void set_index(int idx) { index_ = idx; } + + // for debug + string reventsToString() const; + string eventsToString() const; + + void doNotLogHup() { logHup_ = false; } + + EventLoop* ownerLoop() { return loop_; } + void remove(); + + private: + static string eventsToString(int fd, int ev); + + void update(); + void handleEventWithGuard(Timestamp receiveTime); + + static const int kNoneEvent; + static const int kReadEvent; + static const int kWriteEvent; + + EventLoop* loop_; + const int fd_; + int events_; + int revents_; // it's the received event types of epoll or poll + int index_; // used by Poller. + bool logHup_; + + std::weak_ptr tie_; + bool tied_; + bool eventHandling_; + bool addedToLoop_; + ReadEventCallback readCallback_; + EventCallback writeCallback_; + EventCallback closeCallback_; + EventCallback errorCallback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CHANNEL_H diff --git a/include/muduo/net/Connector.cc b/include/muduo/net/Connector.cc new file mode 100644 index 0000000..0b492ad --- /dev/null +++ b/include/muduo/net/Connector.cc @@ -0,0 +1,226 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Connector.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/SocketsOps.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +const int Connector::kMaxRetryDelayMs; + +Connector::Connector(EventLoop* loop, const InetAddress& serverAddr) + : loop_(loop), + serverAddr_(serverAddr), + connect_(false), + state_(kDisconnected), + retryDelayMs_(kInitRetryDelayMs) +{ + LOG_DEBUG << "ctor[" << this << "]"; +} + +Connector::~Connector() +{ + LOG_DEBUG << "dtor[" << this << "]"; + assert(!channel_); +} + +void Connector::start() +{ + connect_ = true; + loop_->runInLoop(std::bind(&Connector::startInLoop, this)); // FIXME: unsafe +} + +void Connector::startInLoop() +{ + loop_->assertInLoopThread(); + assert(state_ == kDisconnected); + if (connect_) + { + connect(); + } + else + { + LOG_DEBUG << "do not connect"; + } +} + +void Connector::stop() +{ + connect_ = false; + loop_->queueInLoop(std::bind(&Connector::stopInLoop, this)); // FIXME: unsafe + // FIXME: cancel timer +} + +void Connector::stopInLoop() +{ + loop_->assertInLoopThread(); + if (state_ == kConnecting) + { + setState(kDisconnected); + int sockfd = removeAndResetChannel(); + retry(sockfd); + } +} + +void Connector::connect() +{ + int sockfd = sockets::createNonblockingOrDie(serverAddr_.family()); + int ret = sockets::connect(sockfd, serverAddr_.getSockAddr()); + int savedErrno = (ret == 0) ? 0 : errno; + switch (savedErrno) + { + case 0: + case EINPROGRESS: + case EINTR: + case EISCONN: + connecting(sockfd); + break; + + case EAGAIN: + case EADDRINUSE: + case EADDRNOTAVAIL: + case ECONNREFUSED: + case ENETUNREACH: + retry(sockfd); + break; + + case EACCES: + case EPERM: + case EAFNOSUPPORT: + case EALREADY: + case EBADF: + case EFAULT: + case ENOTSOCK: + LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno; + sockets::close(sockfd); + break; + + default: + LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno; + sockets::close(sockfd); + // connectErrorCallback_(); + break; + } +} + +void Connector::restart() +{ + loop_->assertInLoopThread(); + setState(kDisconnected); + retryDelayMs_ = kInitRetryDelayMs; + connect_ = true; + startInLoop(); +} + +void Connector::connecting(int sockfd) +{ + setState(kConnecting); + assert(!channel_); + channel_.reset(new Channel(loop_, sockfd)); + channel_->setWriteCallback( + std::bind(&Connector::handleWrite, this)); // FIXME: unsafe + channel_->setErrorCallback( + std::bind(&Connector::handleError, this)); // FIXME: unsafe + + // channel_->tie(shared_from_this()); is not working, + // as channel_ is not managed by shared_ptr + channel_->enableWriting(); +} + +int Connector::removeAndResetChannel() +{ + channel_->disableAll(); + channel_->remove(); + int sockfd = channel_->fd(); + // Can't reset channel_ here, because we are inside Channel::handleEvent + loop_->queueInLoop(std::bind(&Connector::resetChannel, this)); // FIXME: unsafe + return sockfd; +} + +void Connector::resetChannel() +{ + channel_.reset(); +} + +void Connector::handleWrite() +{ + LOG_TRACE << "Connector::handleWrite " << state_; + + if (state_ == kConnecting) + { + int sockfd = removeAndResetChannel(); + int err = sockets::getSocketError(sockfd); + if (err) + { + LOG_WARN << "Connector::handleWrite - SO_ERROR = " + << err << " " << strerror_tl(err); + retry(sockfd); + } + else if (sockets::isSelfConnect(sockfd)) + { + LOG_WARN << "Connector::handleWrite - Self connect"; + retry(sockfd); + } + else + { + setState(kConnected); + if (connect_) + { + newConnectionCallback_(sockfd); + } + else + { + sockets::close(sockfd); + } + } + } + else + { + // what happened? + assert(state_ == kDisconnected); + } +} + +void Connector::handleError() +{ + LOG_ERROR << "Connector::handleError state=" << state_; + if (state_ == kConnecting) + { + int sockfd = removeAndResetChannel(); + int err = sockets::getSocketError(sockfd); + LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err); + retry(sockfd); + } +} + +void Connector::retry(int sockfd) +{ + sockets::close(sockfd); + setState(kDisconnected); + if (connect_) + { + LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toIpPort() + << " in " << retryDelayMs_ << " milliseconds. "; + loop_->runAfter(retryDelayMs_/1000.0, + std::bind(&Connector::startInLoop, shared_from_this())); + retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs); + } + else + { + LOG_DEBUG << "do not connect"; + } +} + diff --git a/include/muduo/net/Connector.h b/include/muduo/net/Connector.h new file mode 100644 index 0000000..4b79fb2 --- /dev/null +++ b/include/muduo/net/Connector.h @@ -0,0 +1,74 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_CONNECTOR_H +#define MUDUO_NET_CONNECTOR_H + +#include "muduo/base/noncopyable.h" +#include "muduo/net/InetAddress.h" + +#include +#include + +namespace muduo +{ +namespace net +{ + +class Channel; +class EventLoop; + +class Connector : noncopyable, + public std::enable_shared_from_this +{ + public: + typedef std::function NewConnectionCallback; + + Connector(EventLoop* loop, const InetAddress& serverAddr); + ~Connector(); + + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + + void start(); // can be called in any thread + void restart(); // must be called in loop thread + void stop(); // can be called in any thread + + const InetAddress& serverAddress() const { return serverAddr_; } + + private: + enum States { kDisconnected, kConnecting, kConnected }; + static const int kMaxRetryDelayMs = 30*1000; + static const int kInitRetryDelayMs = 500; + + void setState(States s) { state_ = s; } + void startInLoop(); + void stopInLoop(); + void connect(); + void connecting(int sockfd); + void handleWrite(); + void handleError(); + void retry(int sockfd); + int removeAndResetChannel(); + void resetChannel(); + + EventLoop* loop_; + InetAddress serverAddr_; + bool connect_; // atomic + States state_; // FIXME: use atomic variable + std::unique_ptr channel_; + NewConnectionCallback newConnectionCallback_; + int retryDelayMs_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CONNECTOR_H diff --git a/include/muduo/net/Endian.h b/include/muduo/net/Endian.h new file mode 100644 index 0000000..82bd730 --- /dev/null +++ b/include/muduo/net/Endian.h @@ -0,0 +1,65 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_ENDIAN_H +#define MUDUO_NET_ENDIAN_H + +#include +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ + +// the inline assembler code makes type blur, +// so we disable warnings for a while. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wold-style-cast" +inline uint64_t hostToNetwork64(uint64_t host64) +{ + return htobe64(host64); +} + +inline uint32_t hostToNetwork32(uint32_t host32) +{ + return htobe32(host32); +} + +inline uint16_t hostToNetwork16(uint16_t host16) +{ + return htobe16(host16); +} + +inline uint64_t networkToHost64(uint64_t net64) +{ + return be64toh(net64); +} + +inline uint32_t networkToHost32(uint32_t net32) +{ + return be32toh(net32); +} + +inline uint16_t networkToHost16(uint16_t net16) +{ + return be16toh(net16); +} + +#pragma GCC diagnostic pop + +} // namespace sockets +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_ENDIAN_H diff --git a/include/muduo/net/EventLoop.cc b/include/muduo/net/EventLoop.cc new file mode 100644 index 0000000..b3feebe --- /dev/null +++ b/include/muduo/net/EventLoop.cc @@ -0,0 +1,278 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoop.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Mutex.h" +#include "muduo/net/Channel.h" +#include "muduo/net/Poller.h" +#include "muduo/net/SocketsOps.h" +#include "muduo/net/TimerQueue.h" + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ +__thread EventLoop* t_loopInThisThread = 0; + +const int kPollTimeMs = 10000; + +int createEventfd() +{ + int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (evtfd < 0) + { + LOG_SYSERR << "Failed in eventfd"; + abort(); + } + return evtfd; +} + +#pragma GCC diagnostic ignored "-Wold-style-cast" +class IgnoreSigPipe +{ + public: + IgnoreSigPipe() + { + ::signal(SIGPIPE, SIG_IGN); + // LOG_TRACE << "Ignore SIGPIPE"; + } +}; +#pragma GCC diagnostic error "-Wold-style-cast" + +IgnoreSigPipe initObj; +} // namespace + +EventLoop* EventLoop::getEventLoopOfCurrentThread() +{ + return t_loopInThisThread; +} + +EventLoop::EventLoop() + : looping_(false), + quit_(false), + eventHandling_(false), + callingPendingFunctors_(false), + iteration_(0), + threadId_(CurrentThread::tid()), + poller_(Poller::newDefaultPoller(this)), + timerQueue_(new TimerQueue(this)), + wakeupFd_(createEventfd()), + wakeupChannel_(new Channel(this, wakeupFd_)), + currentActiveChannel_(NULL) +{ + LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_; + if (t_loopInThisThread) + { + LOG_FATAL << "Another EventLoop " << t_loopInThisThread + << " exists in this thread " << threadId_; + } + else + { + t_loopInThisThread = this; + } + wakeupChannel_->setReadCallback( + std::bind(&EventLoop::handleRead, this)); + // we are always reading the wakeupfd + wakeupChannel_->enableReading(); +} + +EventLoop::~EventLoop() +{ + LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_ + << " destructs in thread " << CurrentThread::tid(); + wakeupChannel_->disableAll(); + wakeupChannel_->remove(); + ::close(wakeupFd_); + t_loopInThisThread = NULL; +} + +void EventLoop::loop() +{ + assert(!looping_); + assertInLoopThread(); + looping_ = true; + quit_ = false; // FIXME: what if someone calls quit() before loop() ? + LOG_TRACE << "EventLoop " << this << " start looping"; + + while (!quit_) + { + activeChannels_.clear(); + pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); + ++iteration_; + if (Logger::logLevel() <= Logger::TRACE) + { + printActiveChannels(); + } + // TODO sort channel by priority + eventHandling_ = true; + for (Channel* channel : activeChannels_) + { + currentActiveChannel_ = channel; + currentActiveChannel_->handleEvent(pollReturnTime_); + } + currentActiveChannel_ = NULL; + eventHandling_ = false; + doPendingFunctors(); + } + + LOG_TRACE << "EventLoop " << this << " stop looping"; + looping_ = false; +} + +void EventLoop::quit() +{ + quit_ = true; + // There is a chance that loop() just executes while(!quit_) and exits, + // then EventLoop destructs, then we are accessing an invalid object. + // Can be fixed using mutex_ in both places. + if (!isInLoopThread()) + { + wakeup(); + } +} + +void EventLoop::runInLoop(Functor cb) +{ + if (isInLoopThread()) + { + cb(); + } + else + { + queueInLoop(std::move(cb)); + } +} + +void EventLoop::queueInLoop(Functor cb) +{ + { + MutexLockGuard lock(mutex_); + pendingFunctors_.push_back(std::move(cb)); + } + + if (!isInLoopThread() || callingPendingFunctors_) + { + wakeup(); + } +} + +size_t EventLoop::queueSize() const +{ + MutexLockGuard lock(mutex_); + return pendingFunctors_.size(); +} + +TimerId EventLoop::runAt(Timestamp time, TimerCallback cb) +{ + return timerQueue_->addTimer(std::move(cb), time, 0.0); +} + +TimerId EventLoop::runAfter(double delay, TimerCallback cb) +{ + Timestamp time(addTime(Timestamp::now(), delay)); + return runAt(time, std::move(cb)); +} + +TimerId EventLoop::runEvery(double interval, TimerCallback cb) +{ + Timestamp time(addTime(Timestamp::now(), interval)); + return timerQueue_->addTimer(std::move(cb), time, interval); +} + +void EventLoop::cancel(TimerId timerId) +{ + return timerQueue_->cancel(timerId); +} + +void EventLoop::updateChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + poller_->updateChannel(channel); +} + +void EventLoop::removeChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + if (eventHandling_) + { + assert(currentActiveChannel_ == channel || + std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end()); + } + poller_->removeChannel(channel); +} + +bool EventLoop::hasChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + return poller_->hasChannel(channel); +} + +void EventLoop::abortNotInLoopThread() +{ + LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this + << " was created in threadId_ = " << threadId_ + << ", current thread id = " << CurrentThread::tid(); +} + +void EventLoop::wakeup() +{ + uint64_t one = 1; + ssize_t n = sockets::write(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8"; + } +} + +void EventLoop::handleRead() +{ + uint64_t one = 1; + ssize_t n = sockets::read(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8"; + } +} + +void EventLoop::doPendingFunctors() +{ + std::vector functors; + callingPendingFunctors_ = true; + + { + MutexLockGuard lock(mutex_); + functors.swap(pendingFunctors_); + } + + for (const Functor& functor : functors) + { + functor(); + } + callingPendingFunctors_ = false; +} + +void EventLoop::printActiveChannels() const +{ + for (const Channel* channel : activeChannels_) + { + LOG_TRACE << "{" << channel->reventsToString() << "} "; + } +} + diff --git a/include/muduo/net/EventLoop.h b/include/muduo/net/EventLoop.h new file mode 100644 index 0000000..c2c53d3 --- /dev/null +++ b/include/muduo/net/EventLoop.h @@ -0,0 +1,166 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_EVENTLOOP_H +#define MUDUO_NET_EVENTLOOP_H + +#include +#include +#include + +#include + +#include "muduo/base/Mutex.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/TimerId.h" + +namespace muduo +{ +namespace net +{ + +class Channel; +class Poller; +class TimerQueue; + +/// +/// Reactor, at most one per thread. +/// +/// This is an interface class, so don't expose too much details. +class EventLoop : noncopyable +{ + public: + typedef std::function Functor; + + EventLoop(); + ~EventLoop(); // force out-line dtor, for std::unique_ptr members. + + /// + /// Loops forever. + /// + /// Must be called in the same thread as creation of the object. + /// + void loop(); + + /// Quits loop. + /// + /// This is not 100% thread safe, if you call through a raw pointer, + /// better to call through shared_ptr for 100% safety. + void quit(); + + /// + /// Time when poll returns, usually means data arrival. + /// + Timestamp pollReturnTime() const { return pollReturnTime_; } + + int64_t iteration() const { return iteration_; } + + /// Runs callback immediately in the loop thread. + /// It wakes up the loop, and run the cb. + /// If in the same loop thread, cb is run within the function. + /// Safe to call from other threads. + void runInLoop(Functor cb); + /// Queues callback in the loop thread. + /// Runs after finish pooling. + /// Safe to call from other threads. + void queueInLoop(Functor cb); + + size_t queueSize() const; + + // timers + + /// + /// Runs callback at 'time'. + /// Safe to call from other threads. + /// + TimerId runAt(Timestamp time, TimerCallback cb); + /// + /// Runs callback after @c delay seconds. + /// Safe to call from other threads. + /// + TimerId runAfter(double delay, TimerCallback cb); + /// + /// Runs callback every @c interval seconds. + /// Safe to call from other threads. + /// + TimerId runEvery(double interval, TimerCallback cb); + /// + /// Cancels the timer. + /// Safe to call from other threads. + /// + void cancel(TimerId timerId); + + // internal usage + void wakeup(); + void updateChannel(Channel* channel); + void removeChannel(Channel* channel); + bool hasChannel(Channel* channel); + + // pid_t threadId() const { return threadId_; } + void assertInLoopThread() + { + if (!isInLoopThread()) + { + abortNotInLoopThread(); + } + } + bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } + // bool callingPendingFunctors() const { return callingPendingFunctors_; } + bool eventHandling() const { return eventHandling_; } + + void setContext(const boost::any& context) + { context_ = context; } + + const boost::any& getContext() const + { return context_; } + + boost::any* getMutableContext() + { return &context_; } + + static EventLoop* getEventLoopOfCurrentThread(); + + private: + void abortNotInLoopThread(); + void handleRead(); // waked up + void doPendingFunctors(); + + void printActiveChannels() const; // DEBUG + + typedef std::vector ChannelList; + + bool looping_; /* atomic */ + std::atomic quit_; + bool eventHandling_; /* atomic */ + bool callingPendingFunctors_; /* atomic */ + int64_t iteration_; + const pid_t threadId_; + Timestamp pollReturnTime_; + std::unique_ptr poller_; + std::unique_ptr timerQueue_; + int wakeupFd_; + // unlike in TimerQueue, which is an internal class, + // we don't expose Channel to client. + std::unique_ptr wakeupChannel_; + boost::any context_; + + // scratch variables + ChannelList activeChannels_; + Channel* currentActiveChannel_; + + mutable MutexLock mutex_; + std::vector pendingFunctors_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOP_H diff --git a/include/muduo/net/EventLoopThread.cc b/include/muduo/net/EventLoopThread.cc new file mode 100644 index 0000000..c1b6fa5 --- /dev/null +++ b/include/muduo/net/EventLoopThread.cc @@ -0,0 +1,77 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoopThread.h" + +#include "muduo/net/EventLoop.h" + +using namespace muduo; +using namespace muduo::net; + +EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, + const string& name) + : loop_(NULL), + exiting_(false), + thread_(std::bind(&EventLoopThread::threadFunc, this), name), + mutex_(), + cond_(mutex_), + callback_(cb) +{ +} + +EventLoopThread::~EventLoopThread() +{ + exiting_ = true; + if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_. + { + // still a tiny chance to call destructed object, if threadFunc exits just now. + // but when EventLoopThread destructs, usually programming is exiting anyway. + loop_->quit(); + thread_.join(); + } +} + +EventLoop* EventLoopThread::startLoop() +{ + assert(!thread_.started()); + thread_.start(); + + EventLoop* loop = NULL; + { + MutexLockGuard lock(mutex_); + while (loop_ == NULL) + { + cond_.wait(); + } + loop = loop_; + } + + return loop; +} + +void EventLoopThread::threadFunc() +{ + EventLoop loop; + + if (callback_) + { + callback_(&loop); + } + + { + MutexLockGuard lock(mutex_); + loop_ = &loop; + cond_.notify(); + } + + loop.loop(); + //assert(exiting_); + MutexLockGuard lock(mutex_); + loop_ = NULL; +} + diff --git a/include/muduo/net/EventLoopThread.h b/include/muduo/net/EventLoopThread.h new file mode 100644 index 0000000..7e839d7 --- /dev/null +++ b/include/muduo/net/EventLoopThread.h @@ -0,0 +1,50 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_EVENTLOOPTHREAD_H +#define MUDUO_NET_EVENTLOOPTHREAD_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; + +class EventLoopThread : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + + EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(), + const string& name = string()); + ~EventLoopThread(); + EventLoop* startLoop(); + + private: + void threadFunc(); + + EventLoop* loop_ GUARDED_BY(mutex_); + bool exiting_; + Thread thread_; + MutexLock mutex_; + Condition cond_ GUARDED_BY(mutex_); + ThreadInitCallback callback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOPTHREAD_H + diff --git a/include/muduo/net/EventLoopThreadPool.cc b/include/muduo/net/EventLoopThreadPool.cc new file mode 100644 index 0000000..1ee5949 --- /dev/null +++ b/include/muduo/net/EventLoopThreadPool.cc @@ -0,0 +1,97 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoopThreadPool.h" + +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg) + : baseLoop_(baseLoop), + name_(nameArg), + started_(false), + numThreads_(0), + next_(0) +{ +} + +EventLoopThreadPool::~EventLoopThreadPool() +{ + // Don't delete loop, it's stack variable +} + +void EventLoopThreadPool::start(const ThreadInitCallback& cb) +{ + assert(!started_); + baseLoop_->assertInLoopThread(); + + started_ = true; + + for (int i = 0; i < numThreads_; ++i) + { + char buf[name_.size() + 32]; + snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i); + EventLoopThread* t = new EventLoopThread(cb, buf); + threads_.push_back(std::unique_ptr(t)); + loops_.push_back(t->startLoop()); + } + if (numThreads_ == 0 && cb) + { + cb(baseLoop_); + } +} + +EventLoop* EventLoopThreadPool::getNextLoop() +{ + baseLoop_->assertInLoopThread(); + assert(started_); + EventLoop* loop = baseLoop_; + + if (!loops_.empty()) + { + // round-robin + loop = loops_[next_]; + ++next_; + if (implicit_cast(next_) >= loops_.size()) + { + next_ = 0; + } + } + return loop; +} + +EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode) +{ + baseLoop_->assertInLoopThread(); + EventLoop* loop = baseLoop_; + + if (!loops_.empty()) + { + loop = loops_[hashCode % loops_.size()]; + } + return loop; +} + +std::vector EventLoopThreadPool::getAllLoops() +{ + baseLoop_->assertInLoopThread(); + assert(started_); + if (loops_.empty()) + { + return std::vector(1, baseLoop_); + } + else + { + return loops_; + } +} diff --git a/include/muduo/net/EventLoopThreadPool.h b/include/muduo/net/EventLoopThreadPool.h new file mode 100644 index 0000000..7389148 --- /dev/null +++ b/include/muduo/net/EventLoopThreadPool.h @@ -0,0 +1,69 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H +#define MUDUO_NET_EVENTLOOPTHREADPOOL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ + +namespace net +{ + +class EventLoop; +class EventLoopThread; + +class EventLoopThreadPool : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + + EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg); + ~EventLoopThreadPool(); + void setThreadNum(int numThreads) { numThreads_ = numThreads; } + void start(const ThreadInitCallback& cb = ThreadInitCallback()); + + // valid after calling start() + /// round-robin + EventLoop* getNextLoop(); + + /// with the same hash code, it will always return the same EventLoop + EventLoop* getLoopForHash(size_t hashCode); + + std::vector getAllLoops(); + + bool started() const + { return started_; } + + const string& name() const + { return name_; } + + private: + + EventLoop* baseLoop_; + string name_; + bool started_; + int numThreads_; + int next_; + std::vector> threads_; + std::vector loops_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H diff --git a/include/muduo/net/InetAddress.cc b/include/muduo/net/InetAddress.cc new file mode 100644 index 0000000..7c5e0ae --- /dev/null +++ b/include/muduo/net/InetAddress.cc @@ -0,0 +1,149 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/InetAddress.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/SocketsOps.h" + +#include +#include + +// INADDR_ANY use (type)value casting. +#pragma GCC diagnostic ignored "-Wold-style-cast" +static const in_addr_t kInaddrAny = INADDR_ANY; +static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; +#pragma GCC diagnostic error "-Wold-style-cast" + +// /* Structure describing an Internet socket address. */ +// struct sockaddr_in { +// sa_family_t sin_family; /* address family: AF_INET */ +// uint16_t sin_port; /* port in network byte order */ +// struct in_addr sin_addr; /* internet address */ +// }; + +// /* Internet address. */ +// typedef uint32_t in_addr_t; +// struct in_addr { +// in_addr_t s_addr; /* address in network byte order */ +// }; + +// struct sockaddr_in6 { +// sa_family_t sin6_family; /* address family: AF_INET6 */ +// uint16_t sin6_port; /* port in network byte order */ +// uint32_t sin6_flowinfo; /* IPv6 flow information */ +// struct in6_addr sin6_addr; /* IPv6 address */ +// uint32_t sin6_scope_id; /* IPv6 scope-id */ +// }; + +using namespace muduo; +using namespace muduo::net; + +static_assert(sizeof(InetAddress) == sizeof(struct sockaddr_in6), + "InetAddress is same size as sockaddr_in6"); +static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0"); +static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0"); +static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2"); +static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2"); + +InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) +{ + static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0"); + static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0"); + if (ipv6) + { + memZero(&addr6_, sizeof addr6_); + addr6_.sin6_family = AF_INET6; + in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; + addr6_.sin6_addr = ip; + addr6_.sin6_port = sockets::hostToNetwork16(port); + } + else + { + memZero(&addr_, sizeof addr_); + addr_.sin_family = AF_INET; + in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; + addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip); + addr_.sin_port = sockets::hostToNetwork16(port); + } +} + +InetAddress::InetAddress(StringArg ip, uint16_t port, bool ipv6) +{ + if (ipv6 || strchr(ip.c_str(), ':')) + { + memZero(&addr6_, sizeof addr6_); + sockets::fromIpPort(ip.c_str(), port, &addr6_); + } + else + { + memZero(&addr_, sizeof addr_); + sockets::fromIpPort(ip.c_str(), port, &addr_); + } +} + +string InetAddress::toIpPort() const +{ + char buf[64] = ""; + sockets::toIpPort(buf, sizeof buf, getSockAddr()); + return buf; +} + +string InetAddress::toIp() const +{ + char buf[64] = ""; + sockets::toIp(buf, sizeof buf, getSockAddr()); + return buf; +} + +uint32_t InetAddress::ipv4NetEndian() const +{ + assert(family() == AF_INET); + return addr_.sin_addr.s_addr; +} + +uint16_t InetAddress::port() const +{ + return sockets::networkToHost16(portNetEndian()); +} + +static __thread char t_resolveBuffer[64 * 1024]; + +bool InetAddress::resolve(StringArg hostname, InetAddress* out) +{ + assert(out != NULL); + struct hostent hent; + struct hostent* he = NULL; + int herrno = 0; + memZero(&hent, sizeof(hent)); + + int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); + if (ret == 0 && he != NULL) + { + assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); + out->addr_.sin_addr = *reinterpret_cast(he->h_addr); + return true; + } + else + { + if (ret) + { + LOG_SYSERR << "InetAddress::resolve"; + } + return false; + } +} + +void InetAddress::setScopeId(uint32_t scope_id) +{ + if (family() == AF_INET6) + { + addr6_.sin6_scope_id = scope_id; + } +} diff --git a/include/muduo/net/InetAddress.h b/include/muduo/net/InetAddress.h new file mode 100644 index 0000000..c5263a7 --- /dev/null +++ b/include/muduo/net/InetAddress.h @@ -0,0 +1,86 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_INETADDRESS_H +#define MUDUO_NET_INETADDRESS_H + +#include "muduo/base/copyable.h" +#include "muduo/base/StringPiece.h" + +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ +const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); +} + +/// +/// Wrapper of sockaddr_in. +/// +/// This is an POD interface class. +class InetAddress : public muduo::copyable +{ + public: + /// Constructs an endpoint with given port number. + /// Mostly used in TcpServer listening. + explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); + + /// Constructs an endpoint with given ip and port. + /// @c ip should be "1.2.3.4" + InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); + + /// Constructs an endpoint with given struct @c sockaddr_in + /// Mostly used when accepting new connections + explicit InetAddress(const struct sockaddr_in& addr) + : addr_(addr) + { } + + explicit InetAddress(const struct sockaddr_in6& addr) + : addr6_(addr) + { } + + sa_family_t family() const { return addr_.sin_family; } + string toIp() const; + string toIpPort() const; + uint16_t port() const; + + // default copy/assignment are Okay + + const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); } + void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; } + + uint32_t ipv4NetEndian() const; + uint16_t portNetEndian() const { return addr_.sin_port; } + + // resolve hostname to IP address, not changing port or sin_family + // return true on success. + // thread safe + static bool resolve(StringArg hostname, InetAddress* result); + // static std::vector resolveAll(const char* hostname, uint16_t port = 0); + + // set IPv6 ScopeID + void setScopeId(uint32_t scope_id); + + private: + union + { + struct sockaddr_in addr_; + struct sockaddr_in6 addr6_; + }; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INETADDRESS_H diff --git a/include/muduo/net/Poller.cc b/include/muduo/net/Poller.cc new file mode 100644 index 0000000..cfe4c3c --- /dev/null +++ b/include/muduo/net/Poller.cc @@ -0,0 +1,29 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Poller.h" + +#include "muduo/net/Channel.h" + +using namespace muduo; +using namespace muduo::net; + +Poller::Poller(EventLoop* loop) + : ownerLoop_(loop) +{ +} + +Poller::~Poller() = default; + +bool Poller::hasChannel(Channel* channel) const +{ + assertInLoopThread(); + ChannelMap::const_iterator it = channels_.find(channel->fd()); + return it != channels_.end() && it->second == channel; +} + diff --git a/include/muduo/net/Poller.h b/include/muduo/net/Poller.h new file mode 100644 index 0000000..089e60b --- /dev/null +++ b/include/muduo/net/Poller.h @@ -0,0 +1,71 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_H +#define MUDUO_NET_POLLER_H + +#include +#include + +#include "muduo/base/Timestamp.h" +#include "muduo/net/EventLoop.h" + +namespace muduo +{ +namespace net +{ + +class Channel; + +/// +/// Base class for IO Multiplexing +/// +/// This class doesn't own the Channel objects. +class Poller : noncopyable +{ + public: + typedef std::vector ChannelList; + + Poller(EventLoop* loop); + virtual ~Poller(); + + /// Polls the I/O events. + /// Must be called in the loop thread. + virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; + + /// Changes the interested I/O events. + /// Must be called in the loop thread. + virtual void updateChannel(Channel* channel) = 0; + + /// Remove the channel, when it destructs. + /// Must be called in the loop thread. + virtual void removeChannel(Channel* channel) = 0; + + virtual bool hasChannel(Channel* channel) const; + + static Poller* newDefaultPoller(EventLoop* loop); + + void assertInLoopThread() const + { + ownerLoop_->assertInLoopThread(); + } + + protected: + typedef std::map ChannelMap; + ChannelMap channels_; + + private: + EventLoop* ownerLoop_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_POLLER_H diff --git a/include/muduo/net/Socket.cc b/include/muduo/net/Socket.cc new file mode 100644 index 0000000..fc13147 --- /dev/null +++ b/include/muduo/net/Socket.cc @@ -0,0 +1,128 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Socket.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/SocketsOps.h" + +#include +#include +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +Socket::~Socket() +{ + sockets::close(sockfd_); +} + +bool Socket::getTcpInfo(struct tcp_info* tcpi) const +{ + socklen_t len = sizeof(*tcpi); + memZero(tcpi, len); + return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; +} + +bool Socket::getTcpInfoString(char* buf, int len) const +{ + struct tcp_info tcpi; + bool ok = getTcpInfo(&tcpi); + if (ok) + { + snprintf(buf, len, "unrecovered=%u " + "rto=%u ato=%u snd_mss=%u rcv_mss=%u " + "lost=%u retrans=%u rtt=%u rttvar=%u " + "sshthresh=%u cwnd=%u total_retrans=%u", + tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts + tcpi.tcpi_rto, // Retransmit timeout in usec + tcpi.tcpi_ato, // Predicted tick of soft clock in usec + tcpi.tcpi_snd_mss, + tcpi.tcpi_rcv_mss, + tcpi.tcpi_lost, // Lost packets + tcpi.tcpi_retrans, // Retransmitted packets out + tcpi.tcpi_rtt, // Smoothed round trip time in usec + tcpi.tcpi_rttvar, // Medium deviation + tcpi.tcpi_snd_ssthresh, + tcpi.tcpi_snd_cwnd, + tcpi.tcpi_total_retrans); // Total retransmits for entire connection + } + return ok; +} + +void Socket::bindAddress(const InetAddress& addr) +{ + sockets::bindOrDie(sockfd_, addr.getSockAddr()); +} + +void Socket::listen() +{ + sockets::listenOrDie(sockfd_); +} + +int Socket::accept(InetAddress* peeraddr) +{ + struct sockaddr_in6 addr; + memZero(&addr, sizeof addr); + int connfd = sockets::accept(sockfd_, &addr); + if (connfd >= 0) + { + peeraddr->setSockAddrInet6(addr); + } + return connfd; +} + +void Socket::shutdownWrite() +{ + sockets::shutdownWrite(sockfd_); +} + +void Socket::setTcpNoDelay(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + +void Socket::setReuseAddr(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + +void Socket::setReusePort(bool on) +{ +#ifdef SO_REUSEPORT + int optval = on ? 1 : 0; + int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, + &optval, static_cast(sizeof optval)); + if (ret < 0 && on) + { + LOG_SYSERR << "SO_REUSEPORT failed."; + } +#else + if (on) + { + LOG_ERROR << "SO_REUSEPORT is not supported."; + } +#endif +} + +void Socket::setKeepAlive(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + diff --git a/include/muduo/net/Socket.h b/include/muduo/net/Socket.h new file mode 100644 index 0000000..17567be --- /dev/null +++ b/include/muduo/net/Socket.h @@ -0,0 +1,89 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_SOCKET_H +#define MUDUO_NET_SOCKET_H + +#include "muduo/base/noncopyable.h" + +// struct tcp_info is in +struct tcp_info; + +namespace muduo +{ +/// +/// TCP networking. +/// +namespace net +{ + +class InetAddress; + +/// +/// Wrapper of socket file descriptor. +/// +/// It closes the sockfd when desctructs. +/// It's thread safe, all operations are delagated to OS. +class Socket : noncopyable +{ + public: + explicit Socket(int sockfd) + : sockfd_(sockfd) + { } + + // Socket(Socket&&) // move constructor in C++11 + ~Socket(); + + int fd() const { return sockfd_; } + // return true if success. + bool getTcpInfo(struct tcp_info*) const; + bool getTcpInfoString(char* buf, int len) const; + + /// abort if address in use + void bindAddress(const InetAddress& localaddr); + /// abort if address in use + void listen(); + + /// On success, returns a non-negative integer that is + /// a descriptor for the accepted socket, which has been + /// set to non-blocking and close-on-exec. *peeraddr is assigned. + /// On error, -1 is returned, and *peeraddr is untouched. + int accept(InetAddress* peeraddr); + + void shutdownWrite(); + + /// + /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). + /// + void setTcpNoDelay(bool on); + + /// + /// Enable/disable SO_REUSEADDR + /// + void setReuseAddr(bool on); + + /// + /// Enable/disable SO_REUSEPORT + /// + void setReusePort(bool on); + + /// + /// Enable/disable SO_KEEPALIVE + /// + void setKeepAlive(bool on); + + private: + const int sockfd_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_SOCKET_H diff --git a/include/muduo/net/SocketsOps.cc b/include/muduo/net/SocketsOps.cc new file mode 100644 index 0000000..465c507 --- /dev/null +++ b/include/muduo/net/SocketsOps.cc @@ -0,0 +1,316 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/SocketsOps.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Types.h" +#include "muduo/net/Endian.h" + +#include +#include +#include // snprintf +#include +#include // readv +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + +typedef struct sockaddr SA; + + +#if VALGRIND || defined (NO_ACCEPT4) +void setNonBlockAndCloseOnExec(int sockfd) +{ + // non-block + int flags = ::fcntl(sockfd, F_GETFL, 0); + flags |= O_NONBLOCK; + int ret = ::fcntl(sockfd, F_SETFL, flags); + // FIXME check + + // close-on-exec + flags = ::fcntl(sockfd, F_GETFD, 0); + flags |= FD_CLOEXEC; + ret = ::fcntl(sockfd, F_SETFD, flags); + // FIXME check + + (void)ret; +} +#endif + +} // namespace + +const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in6* addr) +{ + return static_cast(implicit_cast(addr)); +} + +struct sockaddr* sockets::sockaddr_cast(struct sockaddr_in6* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr_in* sockets::sockaddr_in_cast(const struct sockaddr* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr_in6* sockets::sockaddr_in6_cast(const struct sockaddr* addr) +{ + return static_cast(implicit_cast(addr)); +} + +int sockets::createNonblockingOrDie(sa_family_t family) +{ +#if VALGRIND + int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP); + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } + + setNonBlockAndCloseOnExec(sockfd); +#else + int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } +#endif + return sockfd; +} + +void sockets::bindOrDie(int sockfd, const struct sockaddr* addr) +{ + int ret = ::bind(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); + if (ret < 0) + { + LOG_SYSFATAL << "sockets::bindOrDie"; + } +} + +void sockets::listenOrDie(int sockfd) +{ + int ret = ::listen(sockfd, SOMAXCONN); + if (ret < 0) + { + LOG_SYSFATAL << "sockets::listenOrDie"; + } +} + +int sockets::accept(int sockfd, struct sockaddr_in6* addr) +{ + socklen_t addrlen = static_cast(sizeof *addr); +#if VALGRIND || defined (NO_ACCEPT4) + int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); + setNonBlockAndCloseOnExec(connfd); +#else + int connfd = ::accept4(sockfd, sockaddr_cast(addr), + &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); +#endif + if (connfd < 0) + { + int savedErrno = errno; + LOG_SYSERR << "Socket::accept"; + switch (savedErrno) + { + case EAGAIN: + case ECONNABORTED: + case EINTR: + case EPROTO: // ??? + case EPERM: + case EMFILE: // per-process lmit of open file desctiptor ??? + // expected errors + errno = savedErrno; + break; + case EBADF: + case EFAULT: + case EINVAL: + case ENFILE: + case ENOBUFS: + case ENOMEM: + case ENOTSOCK: + case EOPNOTSUPP: + // unexpected errors + LOG_FATAL << "unexpected error of ::accept " << savedErrno; + break; + default: + LOG_FATAL << "unknown error of ::accept " << savedErrno; + break; + } + } + return connfd; +} + +int sockets::connect(int sockfd, const struct sockaddr* addr) +{ + return ::connect(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); +} + +ssize_t sockets::read(int sockfd, void *buf, size_t count) +{ + return ::read(sockfd, buf, count); +} + +ssize_t sockets::readv(int sockfd, const struct iovec *iov, int iovcnt) +{ + return ::readv(sockfd, iov, iovcnt); +} + +ssize_t sockets::write(int sockfd, const void *buf, size_t count) +{ + return ::write(sockfd, buf, count); +} + +void sockets::close(int sockfd) +{ + if (::close(sockfd) < 0) + { + LOG_SYSERR << "sockets::close"; + } +} + +void sockets::shutdownWrite(int sockfd) +{ + if (::shutdown(sockfd, SHUT_WR) < 0) + { + LOG_SYSERR << "sockets::shutdownWrite"; + } +} + +void sockets::toIpPort(char* buf, size_t size, + const struct sockaddr* addr) +{ + if (addr->sa_family == AF_INET6) + { + buf[0] = '['; + toIp(buf+1, size-1, addr); + size_t end = ::strlen(buf); + const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); + uint16_t port = sockets::networkToHost16(addr6->sin6_port); + assert(size > end); + snprintf(buf+end, size-end, "]:%u", port); + return; + } + toIp(buf, size, addr); + size_t end = ::strlen(buf); + const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); + uint16_t port = sockets::networkToHost16(addr4->sin_port); + assert(size > end); + snprintf(buf+end, size-end, ":%u", port); +} + +void sockets::toIp(char* buf, size_t size, + const struct sockaddr* addr) +{ + if (addr->sa_family == AF_INET) + { + assert(size >= INET_ADDRSTRLEN); + const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); + ::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast(size)); + } + else if (addr->sa_family == AF_INET6) + { + assert(size >= INET6_ADDRSTRLEN); + const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); + ::inet_ntop(AF_INET6, &addr6->sin6_addr, buf, static_cast(size)); + } +} + +void sockets::fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in* addr) +{ + addr->sin_family = AF_INET; + addr->sin_port = hostToNetwork16(port); + if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) + { + LOG_SYSERR << "sockets::fromIpPort"; + } +} + +void sockets::fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in6* addr) +{ + addr->sin6_family = AF_INET6; + addr->sin6_port = hostToNetwork16(port); + if (::inet_pton(AF_INET6, ip, &addr->sin6_addr) <= 0) + { + LOG_SYSERR << "sockets::fromIpPort"; + } +} + +int sockets::getSocketError(int sockfd) +{ + int optval; + socklen_t optlen = static_cast(sizeof optval); + + if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) + { + return errno; + } + else + { + return optval; + } +} + +struct sockaddr_in6 sockets::getLocalAddr(int sockfd) +{ + struct sockaddr_in6 localaddr; + memZero(&localaddr, sizeof localaddr); + socklen_t addrlen = static_cast(sizeof localaddr); + if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getLocalAddr"; + } + return localaddr; +} + +struct sockaddr_in6 sockets::getPeerAddr(int sockfd) +{ + struct sockaddr_in6 peeraddr; + memZero(&peeraddr, sizeof peeraddr); + socklen_t addrlen = static_cast(sizeof peeraddr); + if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getPeerAddr"; + } + return peeraddr; +} + +bool sockets::isSelfConnect(int sockfd) +{ + struct sockaddr_in6 localaddr = getLocalAddr(sockfd); + struct sockaddr_in6 peeraddr = getPeerAddr(sockfd); + if (localaddr.sin6_family == AF_INET) + { + const struct sockaddr_in* laddr4 = reinterpret_cast(&localaddr); + const struct sockaddr_in* raddr4 = reinterpret_cast(&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) + { + return localaddr.sin6_port == peeraddr.sin6_port + && memcmp(&localaddr.sin6_addr, &peeraddr.sin6_addr, sizeof localaddr.sin6_addr) == 0; + } + else + { + return false; + } +} + diff --git a/include/muduo/net/SocketsOps.h b/include/muduo/net/SocketsOps.h new file mode 100644 index 0000000..9c46597 --- /dev/null +++ b/include/muduo/net/SocketsOps.h @@ -0,0 +1,64 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_SOCKETSOPS_H +#define MUDUO_NET_SOCKETSOPS_H + +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ + +/// +/// Creates a non-blocking socket file descriptor, +/// abort if any error. +int createNonblockingOrDie(sa_family_t family); + +int connect(int sockfd, const struct sockaddr* addr); +void bindOrDie(int sockfd, const struct sockaddr* addr); +void listenOrDie(int sockfd); +int accept(int sockfd, struct sockaddr_in6* addr); +ssize_t read(int sockfd, void *buf, size_t count); +ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); +ssize_t write(int sockfd, const void *buf, size_t count); +void close(int sockfd); +void shutdownWrite(int sockfd); + +void toIpPort(char* buf, size_t size, + const struct sockaddr* addr); +void toIp(char* buf, size_t size, + const struct sockaddr* addr); + +void fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in* addr); +void fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in6* addr); + +int getSocketError(int sockfd); + +const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); +const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); +struct sockaddr* sockaddr_cast(struct sockaddr_in6* addr); +const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); +const struct sockaddr_in6* sockaddr_in6_cast(const struct sockaddr* addr); + +struct sockaddr_in6 getLocalAddr(int sockfd); +struct sockaddr_in6 getPeerAddr(int sockfd); +bool isSelfConnect(int sockfd); + +} // namespace sockets +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_SOCKETSOPS_H diff --git a/include/muduo/net/TcpClient.cc b/include/muduo/net/TcpClient.cc new file mode 100644 index 0000000..1e668b3 --- /dev/null +++ b/include/muduo/net/TcpClient.cc @@ -0,0 +1,181 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/TcpClient.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Connector.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/SocketsOps.h" + +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +// TcpClient::TcpClient(EventLoop* loop) +// : loop_(loop) +// { +// } + +// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) +// : loop_(CHECK_NOTNULL(loop)), +// serverAddr_(host, port) +// { +// } + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn) +{ + loop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); +} + +void removeConnector(const ConnectorPtr& connector) +{ + //connector-> +} + +} // namespace detail +} // namespace net +} // namespace muduo + +TcpClient::TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& nameArg) + : loop_(CHECK_NOTNULL(loop)), + connector_(new Connector(loop, serverAddr)), + name_(nameArg), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), + retry_(false), + connect_(true), + nextConnId_(1) +{ + connector_->setNewConnectionCallback( + std::bind(&TcpClient::newConnection, this, _1)); + // FIXME setConnectFailedCallback + LOG_INFO << "TcpClient::TcpClient[" << name_ + << "] - connector " << get_pointer(connector_); +} + +TcpClient::~TcpClient() +{ + LOG_INFO << "TcpClient::~TcpClient[" << name_ + << "] - connector " << get_pointer(connector_); + TcpConnectionPtr conn; + bool unique = false; + { + MutexLockGuard lock(mutex_); + unique = connection_.unique(); + conn = connection_; + } + if (conn) + { + assert(loop_ == conn->getLoop()); + // FIXME: not 100% safe, if we are in different thread + CloseCallback cb = std::bind(&detail::removeConnection, loop_, _1); + loop_->runInLoop( + std::bind(&TcpConnection::setCloseCallback, conn, cb)); + if (unique) + { + conn->forceClose(); + } + } + else + { + connector_->stop(); + // FIXME: HACK + loop_->runAfter(1, std::bind(&detail::removeConnector, connector_)); + } +} + +void TcpClient::connect() +{ + // FIXME: check state + LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to " + << connector_->serverAddress().toIpPort(); + connect_ = true; + connector_->start(); +} + +void TcpClient::disconnect() +{ + connect_ = false; + + { + MutexLockGuard lock(mutex_); + if (connection_) + { + connection_->shutdown(); + } + } +} + +void TcpClient::stop() +{ + connect_ = false; + connector_->stop(); +} + +void TcpClient::newConnection(int sockfd) +{ + loop_->assertInLoopThread(); + InetAddress peerAddr(sockets::getPeerAddr(sockfd)); + char buf[32]; + snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toIpPort().c_str(), nextConnId_); + ++nextConnId_; + string connName = name_ + buf; + + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection + // FIXME use make_shared if necessary + TcpConnectionPtr conn(new TcpConnection(loop_, + connName, + sockfd, + localAddr, + peerAddr)); + + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); + conn->setCloseCallback( + std::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe + { + MutexLockGuard lock(mutex_); + connection_ = conn; + } + conn->connectEstablished(); +} + +void TcpClient::removeConnection(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + assert(loop_ == conn->getLoop()); + + { + MutexLockGuard lock(mutex_); + assert(connection_ == conn); + connection_.reset(); + } + + loop_->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); + if (retry_ && connect_) + { + LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to " + << connector_->serverAddress().toIpPort(); + connector_->restart(); + } +} + diff --git a/include/muduo/net/TcpClient.h b/include/muduo/net/TcpClient.h new file mode 100644 index 0000000..c498cb3 --- /dev/null +++ b/include/muduo/net/TcpClient.h @@ -0,0 +1,90 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPCLIENT_H +#define MUDUO_NET_TCPCLIENT_H + +#include "muduo/base/Mutex.h" +#include "muduo/net/TcpConnection.h" + +namespace muduo +{ +namespace net +{ + +class Connector; +typedef std::shared_ptr ConnectorPtr; + +class TcpClient : noncopyable +{ + public: + // TcpClient(EventLoop* loop); + // TcpClient(EventLoop* loop, const string& host, uint16_t port); + TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& nameArg); + ~TcpClient(); // force out-line dtor, for std::unique_ptr members. + + void connect(); + void disconnect(); + void stop(); + + TcpConnectionPtr connection() const + { + MutexLockGuard lock(mutex_); + return connection_; + } + + EventLoop* getLoop() const { return loop_; } + bool retry() const { return retry_; } + void enableRetry() { retry_ = true; } + + const string& name() const + { return name_; } + + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(ConnectionCallback cb) + { connectionCallback_ = std::move(cb); } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(MessageCallback cb) + { messageCallback_ = std::move(cb); } + + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(WriteCompleteCallback cb) + { writeCompleteCallback_ = std::move(cb); } + + private: + /// Not thread safe, but in loop + void newConnection(int sockfd); + /// Not thread safe, but in loop + void removeConnection(const TcpConnectionPtr& conn); + + EventLoop* loop_; + ConnectorPtr connector_; // avoid revealing Connector + const string name_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + bool retry_; // atomic + bool connect_; // atomic + // always in loop thread + int nextConnId_; + mutable MutexLock mutex_; + TcpConnectionPtr connection_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPCLIENT_H diff --git a/include/muduo/net/TcpConnection.cc b/include/muduo/net/TcpConnection.cc new file mode 100644 index 0000000..37f58a4 --- /dev/null +++ b/include/muduo/net/TcpConnection.cc @@ -0,0 +1,429 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/TcpConnection.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/WeakCallback.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/Socket.h" +#include "muduo/net/SocketsOps.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn) +{ + LOG_TRACE << conn->localAddress().toIpPort() << " -> " + << conn->peerAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + // do not call conn->forceClose(), because some users want to register message callback only. +} + +void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, + Buffer* buf, + Timestamp) +{ + buf->retrieveAll(); +} + +TcpConnection::TcpConnection(EventLoop* loop, + const string& nameArg, + int sockfd, + const InetAddress& localAddr, + const InetAddress& peerAddr) + : loop_(CHECK_NOTNULL(loop)), + name_(nameArg), + state_(kConnecting), + reading_(true), + socket_(new Socket(sockfd)), + channel_(new Channel(loop, sockfd)), + localAddr_(localAddr), + peerAddr_(peerAddr), + highWaterMark_(64*1024*1024) +{ + channel_->setReadCallback( + std::bind(&TcpConnection::handleRead, this, _1)); + channel_->setWriteCallback( + std::bind(&TcpConnection::handleWrite, this)); + channel_->setCloseCallback( + std::bind(&TcpConnection::handleClose, this)); + channel_->setErrorCallback( + std::bind(&TcpConnection::handleError, this)); + LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this + << " fd=" << sockfd; + socket_->setKeepAlive(true); +} + +TcpConnection::~TcpConnection() +{ + LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this + << " fd=" << channel_->fd() + << " state=" << stateToString(); + assert(state_ == kDisconnected); +} + +bool TcpConnection::getTcpInfo(struct tcp_info* tcpi) const +{ + return socket_->getTcpInfo(tcpi); +} + +string TcpConnection::getTcpInfoString() const +{ + char buf[1024]; + buf[0] = '\0'; + socket_->getTcpInfoString(buf, sizeof buf); + return buf; +} + +void TcpConnection::send(const void* data, int len) +{ + send(StringPiece(static_cast(data), len)); +} + +void TcpConnection::send(const StringPiece& message) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(message); + } + else + { + void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; + loop_->runInLoop( + std::bind(fp, + this, // FIXME + message.as_string())); + //std::forward(message))); + } + } +} + +// FIXME efficiency!!! +void TcpConnection::send(Buffer* buf) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(buf->peek(), buf->readableBytes()); + buf->retrieveAll(); + } + else + { + void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; + loop_->runInLoop( + std::bind(fp, + this, // FIXME + buf->retrieveAllAsString())); + //std::forward(message))); + } + } +} + +void TcpConnection::sendInLoop(const StringPiece& message) +{ + sendInLoop(message.data(), message.size()); +} + +void TcpConnection::sendInLoop(const void* data, size_t len) +{ + loop_->assertInLoopThread(); + ssize_t nwrote = 0; + size_t remaining = len; + bool faultError = false; + if (state_ == kDisconnected) + { + LOG_WARN << "disconnected, give up writing"; + return; + } + // if no thing in output queue, try writing directly + if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) + { + nwrote = sockets::write(channel_->fd(), data, len); + if (nwrote >= 0) + { + remaining = len - nwrote; + if (remaining == 0 && writeCompleteCallback_) + { + loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); + } + } + else // nwrote < 0 + { + nwrote = 0; + if (errno != EWOULDBLOCK) + { + LOG_SYSERR << "TcpConnection::sendInLoop"; + if (errno == EPIPE || errno == ECONNRESET) // FIXME: any others? + { + faultError = true; + } + } + } + } + + assert(remaining <= len); + if (!faultError && remaining > 0) + { + size_t oldLen = outputBuffer_.readableBytes(); + if (oldLen + remaining >= highWaterMark_ + && oldLen < highWaterMark_ + && highWaterMarkCallback_) + { + loop_->queueInLoop(std::bind(highWaterMarkCallback_, shared_from_this(), oldLen + remaining)); + } + outputBuffer_.append(static_cast(data)+nwrote, remaining); + if (!channel_->isWriting()) + { + channel_->enableWriting(); + } + } +} + +void TcpConnection::shutdown() +{ + // FIXME: use compare and swap + if (state_ == kConnected) + { + setState(kDisconnecting); + // FIXME: shared_from_this()? + loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this)); + } +} + +void TcpConnection::shutdownInLoop() +{ + loop_->assertInLoopThread(); + if (!channel_->isWriting()) + { + // we are not writing + socket_->shutdownWrite(); + } +} + +// void TcpConnection::shutdownAndForceCloseAfter(double seconds) +// { +// // FIXME: use compare and swap +// if (state_ == kConnected) +// { +// setState(kDisconnecting); +// loop_->runInLoop(std::bind(&TcpConnection::shutdownAndForceCloseInLoop, this, seconds)); +// } +// } + +// void TcpConnection::shutdownAndForceCloseInLoop(double seconds) +// { +// loop_->assertInLoopThread(); +// if (!channel_->isWriting()) +// { +// // we are not writing +// socket_->shutdownWrite(); +// } +// loop_->runAfter( +// seconds, +// makeWeakCallback(shared_from_this(), +// &TcpConnection::forceCloseInLoop)); +// } + +void TcpConnection::forceClose() +{ + // FIXME: use compare and swap + if (state_ == kConnected || state_ == kDisconnecting) + { + setState(kDisconnecting); + loop_->queueInLoop(std::bind(&TcpConnection::forceCloseInLoop, shared_from_this())); + } +} + +void TcpConnection::forceCloseWithDelay(double seconds) +{ + if (state_ == kConnected || state_ == kDisconnecting) + { + setState(kDisconnecting); + loop_->runAfter( + seconds, + makeWeakCallback(shared_from_this(), + &TcpConnection::forceClose)); // not forceCloseInLoop to avoid race condition + } +} + +void TcpConnection::forceCloseInLoop() +{ + loop_->assertInLoopThread(); + if (state_ == kConnected || state_ == kDisconnecting) + { + // as if we received 0 byte in handleRead(); + handleClose(); + } +} + +const char* TcpConnection::stateToString() const +{ + switch (state_) + { + case kDisconnected: + return "kDisconnected"; + case kConnecting: + return "kConnecting"; + case kConnected: + return "kConnected"; + case kDisconnecting: + return "kDisconnecting"; + default: + return "unknown state"; + } +} + +void TcpConnection::setTcpNoDelay(bool on) +{ + socket_->setTcpNoDelay(on); +} + +void TcpConnection::startRead() +{ + loop_->runInLoop(std::bind(&TcpConnection::startReadInLoop, this)); +} + +void TcpConnection::startReadInLoop() +{ + loop_->assertInLoopThread(); + if (!reading_ || !channel_->isReading()) + { + channel_->enableReading(); + reading_ = true; + } +} + +void TcpConnection::stopRead() +{ + loop_->runInLoop(std::bind(&TcpConnection::stopReadInLoop, this)); +} + +void TcpConnection::stopReadInLoop() +{ + loop_->assertInLoopThread(); + if (reading_ || channel_->isReading()) + { + channel_->disableReading(); + reading_ = false; + } +} + +void TcpConnection::connectEstablished() +{ + loop_->assertInLoopThread(); + assert(state_ == kConnecting); + setState(kConnected); + channel_->tie(shared_from_this()); + channel_->enableReading(); + + connectionCallback_(shared_from_this()); +} + +void TcpConnection::connectDestroyed() +{ + loop_->assertInLoopThread(); + if (state_ == kConnected) + { + setState(kDisconnected); + channel_->disableAll(); + + connectionCallback_(shared_from_this()); + } + channel_->remove(); +} + +void TcpConnection::handleRead(Timestamp receiveTime) +{ + loop_->assertInLoopThread(); + int savedErrno = 0; + ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno); + if (n > 0) + { + messageCallback_(shared_from_this(), &inputBuffer_, receiveTime); + } + else if (n == 0) + { + handleClose(); + } + else + { + errno = savedErrno; + LOG_SYSERR << "TcpConnection::handleRead"; + handleError(); + } +} + +void TcpConnection::handleWrite() +{ + loop_->assertInLoopThread(); + if (channel_->isWriting()) + { + ssize_t n = sockets::write(channel_->fd(), + outputBuffer_.peek(), + outputBuffer_.readableBytes()); + if (n > 0) + { + outputBuffer_.retrieve(n); + if (outputBuffer_.readableBytes() == 0) + { + channel_->disableWriting(); + if (writeCompleteCallback_) + { + loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); + } + if (state_ == kDisconnecting) + { + shutdownInLoop(); + } + } + } + else + { + LOG_SYSERR << "TcpConnection::handleWrite"; + // if (state_ == kDisconnecting) + // { + // shutdownInLoop(); + // } + } + } + else + { + LOG_TRACE << "Connection fd = " << channel_->fd() + << " is down, no more writing"; + } +} + +void TcpConnection::handleClose() +{ + loop_->assertInLoopThread(); + LOG_TRACE << "fd = " << channel_->fd() << " state = " << stateToString(); + assert(state_ == kConnected || state_ == kDisconnecting); + // we don't close fd, leave it to dtor, so we can find leaks easily. + setState(kDisconnected); + channel_->disableAll(); + + TcpConnectionPtr guardThis(shared_from_this()); + connectionCallback_(guardThis); + // must be the last line + closeCallback_(guardThis); +} + +void TcpConnection::handleError() +{ + int err = sockets::getSocketError(channel_->fd()); + LOG_ERROR << "TcpConnection::handleError [" << name_ + << "] - SO_ERROR = " << err << " " << strerror_tl(err); +} + diff --git a/include/muduo/net/TcpConnection.h b/include/muduo/net/TcpConnection.h new file mode 100644 index 0000000..cb76331 --- /dev/null +++ b/include/muduo/net/TcpConnection.h @@ -0,0 +1,161 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPCONNECTION_H +#define MUDUO_NET_TCPCONNECTION_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/Buffer.h" +#include "muduo/net/InetAddress.h" + +#include + +#include + +// struct tcp_info is in +struct tcp_info; + +namespace muduo +{ +namespace net +{ + +class Channel; +class EventLoop; +class Socket; + +/// +/// TCP connection, for both client and server usage. +/// +/// This is an interface class, so don't expose too much details. +class TcpConnection : noncopyable, + public std::enable_shared_from_this +{ + public: + /// Constructs a TcpConnection with a connected sockfd + /// + /// User should not create this object. + TcpConnection(EventLoop* loop, + const string& name, + int sockfd, + const InetAddress& localAddr, + const InetAddress& peerAddr); + ~TcpConnection(); + + EventLoop* getLoop() const { return loop_; } + const string& name() const { return name_; } + const InetAddress& localAddress() const { return localAddr_; } + const InetAddress& peerAddress() const { return peerAddr_; } + bool connected() const { return state_ == kConnected; } + bool disconnected() const { return state_ == kDisconnected; } + // return true if success. + bool getTcpInfo(struct tcp_info*) const; + string getTcpInfoString() const; + + // void send(string&& message); // C++11 + void send(const void* message, int len); + void send(const StringPiece& message); + // void send(Buffer&& message); // C++11 + void send(Buffer* message); // this one will swap data + void shutdown(); // NOT thread safe, no simultaneous calling + // void shutdownAndForceCloseAfter(double seconds); // NOT thread safe, no simultaneous calling + void forceClose(); + void forceCloseWithDelay(double seconds); + void setTcpNoDelay(bool on); + // reading or not + void startRead(); + void stopRead(); + bool isReading() const { return reading_; }; // NOT thread safe, may race with start/stopReadInLoop + + void setContext(const boost::any& context) + { context_ = context; } + + const boost::any& getContext() const + { return context_; } + + boost::any* getMutableContext() + { return &context_; } + + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } + + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + + void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark) + { highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark; } + + /// Advanced interface + Buffer* inputBuffer() + { return &inputBuffer_; } + + Buffer* outputBuffer() + { return &outputBuffer_; } + + /// Internal use only. + void setCloseCallback(const CloseCallback& cb) + { closeCallback_ = cb; } + + // called when TcpServer accepts a new connection + void connectEstablished(); // should be called only once + // called when TcpServer has removed me from its map + void connectDestroyed(); // should be called only once + + private: + enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting }; + void handleRead(Timestamp receiveTime); + void handleWrite(); + void handleClose(); + void handleError(); + // void sendInLoop(string&& message); + void sendInLoop(const StringPiece& message); + void sendInLoop(const void* message, size_t len); + void shutdownInLoop(); + // void shutdownAndForceCloseInLoop(double seconds); + void forceCloseInLoop(); + void setState(StateE s) { state_ = s; } + const char* stateToString() const; + void startReadInLoop(); + void stopReadInLoop(); + + EventLoop* loop_; + const string name_; + StateE state_; // FIXME: use atomic variable + bool reading_; + // we don't expose those classes to client. + std::unique_ptr socket_; + std::unique_ptr channel_; + const InetAddress localAddr_; + const InetAddress peerAddr_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + HighWaterMarkCallback highWaterMarkCallback_; + CloseCallback closeCallback_; + size_t highWaterMark_; + Buffer inputBuffer_; + Buffer outputBuffer_; // FIXME: use list as output buffer. + boost::any context_; + // FIXME: creationTime_, lastReceiveTime_ + // bytesReceived_, bytesSent_ +}; + +typedef std::shared_ptr TcpConnectionPtr; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPCONNECTION_H diff --git a/include/muduo/net/TcpServer.cc b/include/muduo/net/TcpServer.cc new file mode 100644 index 0000000..e4f8e24 --- /dev/null +++ b/include/muduo/net/TcpServer.cc @@ -0,0 +1,118 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/TcpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Acceptor.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThreadPool.h" +#include "muduo/net/SocketsOps.h" + +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +TcpServer::TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& nameArg, + Option option) + : loop_(CHECK_NOTNULL(loop)), + ipPort_(listenAddr.toIpPort()), + name_(nameArg), + acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), + threadPool_(new EventLoopThreadPool(loop, name_)), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), + nextConnId_(1) +{ + acceptor_->setNewConnectionCallback( + std::bind(&TcpServer::newConnection, this, _1, _2)); +} + +TcpServer::~TcpServer() +{ + loop_->assertInLoopThread(); + LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; + + for (auto& item : connections_) + { + TcpConnectionPtr conn(item.second); + item.second.reset(); + conn->getLoop()->runInLoop( + std::bind(&TcpConnection::connectDestroyed, conn)); + } +} + +void TcpServer::setThreadNum(int numThreads) +{ + assert(0 <= numThreads); + threadPool_->setThreadNum(numThreads); +} + +void TcpServer::start() +{ + if (started_.getAndSet(1) == 0) + { + threadPool_->start(threadInitCallback_); + + assert(!acceptor_->listening()); + loop_->runInLoop( + std::bind(&Acceptor::listen, get_pointer(acceptor_))); + } +} + +void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) +{ + loop_->assertInLoopThread(); + EventLoop* ioLoop = threadPool_->getNextLoop(); + char buf[64]; + snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_); + ++nextConnId_; + string connName = name_ + buf; + + LOG_INFO << "TcpServer::newConnection [" << name_ + << "] - new connection [" << connName + << "] from " << peerAddr.toIpPort(); + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection + // FIXME use make_shared if necessary + TcpConnectionPtr conn(new TcpConnection(ioLoop, + connName, + sockfd, + localAddr, + peerAddr)); + connections_[connName] = conn; + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); + conn->setCloseCallback( + std::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe + ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn)); +} + +void TcpServer::removeConnection(const TcpConnectionPtr& conn) +{ + // FIXME: unsafe + loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn)); +} + +void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ + << "] - connection " << conn->name(); + size_t n = connections_.erase(conn->name()); + (void)n; + assert(n == 1); + EventLoop* ioLoop = conn->getLoop(); + ioLoop->queueInLoop( + std::bind(&TcpConnection::connectDestroyed, conn)); +} + diff --git a/include/muduo/net/TcpServer.h b/include/muduo/net/TcpServer.h new file mode 100644 index 0000000..3fbfead --- /dev/null +++ b/include/muduo/net/TcpServer.h @@ -0,0 +1,120 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPSERVER_H +#define MUDUO_NET_TCPSERVER_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Types.h" +#include "muduo/net/TcpConnection.h" + +#include + +namespace muduo +{ +namespace net +{ + +class Acceptor; +class EventLoop; +class EventLoopThreadPool; + +/// +/// TCP server, supports single-threaded and thread-pool models. +/// +/// This is an interface class, so don't expose too much details. +class TcpServer : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + enum Option + { + kNoReusePort, + kReusePort, + }; + + //TcpServer(EventLoop* loop, const InetAddress& listenAddr); + TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& nameArg, + Option option = kNoReusePort); + ~TcpServer(); // force out-line dtor, for std::unique_ptr members. + + const string& ipPort() const { return ipPort_; } + const string& name() const { return name_; } + EventLoop* getLoop() const { return loop_; } + + /// Set the number of threads for handling input. + /// + /// Always accepts new connection in loop's thread. + /// Must be called before @c start + /// @param numThreads + /// - 0 means all I/O in loop's thread, no thread will created. + /// this is the default value. + /// - 1 means all I/O in another thread. + /// - N means a thread pool with N threads, new connections + /// are assigned on a round-robin basis. + void setThreadNum(int numThreads); + void setThreadInitCallback(const ThreadInitCallback& cb) + { threadInitCallback_ = cb; } + /// valid after calling start() + std::shared_ptr threadPool() + { return threadPool_; } + + /// Starts the server if it's not listening. + /// + /// It's harmless to call it multiple times. + /// Thread safe. + void start(); + + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } + + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + + private: + /// Not thread safe, but in loop + void newConnection(int sockfd, const InetAddress& peerAddr); + /// Thread safe. + void removeConnection(const TcpConnectionPtr& conn); + /// Not thread safe, but in loop + void removeConnectionInLoop(const TcpConnectionPtr& conn); + + typedef std::map ConnectionMap; + + EventLoop* loop_; // the acceptor loop + const string ipPort_; + const string name_; + std::unique_ptr acceptor_; // avoid revealing Acceptor + std::shared_ptr threadPool_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + ThreadInitCallback threadInitCallback_; + AtomicInt32 started_; + // always in loop thread + int nextConnId_; + ConnectionMap connections_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPSERVER_H diff --git a/include/muduo/net/Timer.cc b/include/muduo/net/Timer.cc new file mode 100644 index 0000000..a4d4433 --- /dev/null +++ b/include/muduo/net/Timer.cc @@ -0,0 +1,26 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Timer.h" + +using namespace muduo; +using namespace muduo::net; + +AtomicInt64 Timer::s_numCreated_; + +void Timer::restart(Timestamp now) +{ + if (repeat_) + { + expiration_ = addTime(now, interval_); + } + else + { + expiration_ = Timestamp::invalid(); + } +} diff --git a/include/muduo/net/Timer.h b/include/muduo/net/Timer.h new file mode 100644 index 0000000..904584e --- /dev/null +++ b/include/muduo/net/Timer.h @@ -0,0 +1,63 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_TIMER_H +#define MUDUO_NET_TIMER_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" + +namespace muduo +{ +namespace net +{ + +/// +/// Internal class for timer event. +/// +class Timer : noncopyable +{ + public: + Timer(TimerCallback cb, Timestamp when, double interval) + : callback_(std::move(cb)), + expiration_(when), + interval_(interval), + repeat_(interval > 0.0), + sequence_(s_numCreated_.incrementAndGet()) + { } + + void run() const + { + callback_(); + } + + Timestamp expiration() const { return expiration_; } + bool repeat() const { return repeat_; } + int64_t sequence() const { return sequence_; } + + void restart(Timestamp now); + + static int64_t numCreated() { return s_numCreated_.get(); } + + private: + const TimerCallback callback_; + Timestamp expiration_; + const double interval_; + const bool repeat_; + const int64_t sequence_; + + static AtomicInt64 s_numCreated_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TIMER_H diff --git a/include/muduo/net/TimerId.h b/include/muduo/net/TimerId.h new file mode 100644 index 0000000..fcc5264 --- /dev/null +++ b/include/muduo/net/TimerId.h @@ -0,0 +1,53 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TIMERID_H +#define MUDUO_NET_TIMERID_H + +#include "muduo/base/copyable.h" + +namespace muduo +{ +namespace net +{ + +class Timer; + +/// +/// An opaque identifier, for canceling Timer. +/// +class TimerId : public muduo::copyable +{ + public: + TimerId() + : timer_(NULL), + sequence_(0) + { + } + + TimerId(Timer* timer, int64_t seq) + : timer_(timer), + sequence_(seq) + { + } + + // default copy-ctor, dtor and assignment are okay + + friend class TimerQueue; + + private: + Timer* timer_; + int64_t sequence_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TIMERID_H diff --git a/include/muduo/net/TimerQueue.cc b/include/muduo/net/TimerQueue.cc new file mode 100644 index 0000000..89119ae --- /dev/null +++ b/include/muduo/net/TimerQueue.cc @@ -0,0 +1,260 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +#include "muduo/net/TimerQueue.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/Timer.h" +#include "muduo/net/TimerId.h" + +#include +#include + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +int createTimerfd() +{ + int timerfd = ::timerfd_create(CLOCK_MONOTONIC, + TFD_NONBLOCK | TFD_CLOEXEC); + if (timerfd < 0) + { + LOG_SYSFATAL << "Failed in timerfd_create"; + } + return timerfd; +} + +struct timespec howMuchTimeFromNow(Timestamp when) +{ + int64_t microseconds = when.microSecondsSinceEpoch() + - Timestamp::now().microSecondsSinceEpoch(); + if (microseconds < 100) + { + microseconds = 100; + } + struct timespec ts; + ts.tv_sec = static_cast( + microseconds / Timestamp::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast( + (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); + return ts; +} + +void readTimerfd(int timerfd, Timestamp now) +{ + uint64_t howmany; + ssize_t n = ::read(timerfd, &howmany, sizeof howmany); + LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); + if (n != sizeof howmany) + { + LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; + } +} + +void resetTimerfd(int timerfd, Timestamp expiration) +{ + // wake up loop by timerfd_settime() + struct itimerspec newValue; + struct itimerspec oldValue; + memZero(&newValue, sizeof newValue); + memZero(&oldValue, sizeof oldValue); + newValue.it_value = howMuchTimeFromNow(expiration); + int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); + if (ret) + { + LOG_SYSERR << "timerfd_settime()"; + } +} + +} // namespace detail +} // namespace net +} // namespace muduo + +using namespace muduo; +using namespace muduo::net; +using namespace muduo::net::detail; + +TimerQueue::TimerQueue(EventLoop* loop) + : loop_(loop), + timerfd_(createTimerfd()), + timerfdChannel_(loop, timerfd_), + timers_(), + callingExpiredTimers_(false) +{ + timerfdChannel_.setReadCallback( + std::bind(&TimerQueue::handleRead, this)); + // we are always reading the timerfd, we disarm it with timerfd_settime. + timerfdChannel_.enableReading(); +} + +TimerQueue::~TimerQueue() +{ + timerfdChannel_.disableAll(); + timerfdChannel_.remove(); + ::close(timerfd_); + // do not remove channel, since we're in EventLoop::dtor(); + for (const Entry& timer : timers_) + { + delete timer.second; + } +} + +TimerId TimerQueue::addTimer(TimerCallback cb, + Timestamp when, + double interval) +{ + Timer* timer = new Timer(std::move(cb), when, interval); + loop_->runInLoop( + std::bind(&TimerQueue::addTimerInLoop, this, timer)); + return TimerId(timer, timer->sequence()); +} + +void TimerQueue::cancel(TimerId timerId) +{ + loop_->runInLoop( + std::bind(&TimerQueue::cancelInLoop, this, timerId)); +} + +void TimerQueue::addTimerInLoop(Timer* timer) +{ + loop_->assertInLoopThread(); + bool earliestChanged = insert(timer); + + if (earliestChanged) + { + resetTimerfd(timerfd_, timer->expiration()); + } +} + +void TimerQueue::cancelInLoop(TimerId timerId) +{ + loop_->assertInLoopThread(); + assert(timers_.size() == activeTimers_.size()); + ActiveTimer timer(timerId.timer_, timerId.sequence_); + ActiveTimerSet::iterator it = activeTimers_.find(timer); + if (it != activeTimers_.end()) + { + size_t n = timers_.erase(Entry(it->first->expiration(), it->first)); + assert(n == 1); (void)n; + delete it->first; // FIXME: no delete please + activeTimers_.erase(it); + } + else if (callingExpiredTimers_) + { + cancelingTimers_.insert(timer); + } + assert(timers_.size() == activeTimers_.size()); +} + +void TimerQueue::handleRead() +{ + loop_->assertInLoopThread(); + Timestamp now(Timestamp::now()); + readTimerfd(timerfd_, now); + + std::vector expired = getExpired(now); + + callingExpiredTimers_ = true; + cancelingTimers_.clear(); + // safe to callback outside critical section + for (const Entry& it : expired) + { + it.second->run(); + } + callingExpiredTimers_ = false; + + reset(expired, now); +} + +std::vector TimerQueue::getExpired(Timestamp now) +{ + assert(timers_.size() == activeTimers_.size()); + std::vector expired; + Entry sentry(now, reinterpret_cast(UINTPTR_MAX)); + TimerList::iterator end = timers_.lower_bound(sentry); + assert(end == timers_.end() || now < end->first); + std::copy(timers_.begin(), end, back_inserter(expired)); + timers_.erase(timers_.begin(), end); + + for (const Entry& it : expired) + { + ActiveTimer timer(it.second, it.second->sequence()); + size_t n = activeTimers_.erase(timer); + assert(n == 1); (void)n; + } + + assert(timers_.size() == activeTimers_.size()); + return expired; +} + +void TimerQueue::reset(const std::vector& expired, Timestamp now) +{ + Timestamp nextExpire; + + for (const Entry& it : expired) + { + ActiveTimer timer(it.second, it.second->sequence()); + if (it.second->repeat() + && cancelingTimers_.find(timer) == cancelingTimers_.end()) + { + it.second->restart(now); + insert(it.second); + } + else + { + // FIXME move to a free list + delete it.second; // FIXME: no delete please + } + } + + if (!timers_.empty()) + { + nextExpire = timers_.begin()->second->expiration(); + } + + if (nextExpire.valid()) + { + resetTimerfd(timerfd_, nextExpire); + } +} + +bool TimerQueue::insert(Timer* timer) +{ + loop_->assertInLoopThread(); + assert(timers_.size() == activeTimers_.size()); + bool earliestChanged = false; + Timestamp when = timer->expiration(); + TimerList::iterator it = timers_.begin(); + if (it == timers_.end() || when < it->first) + { + earliestChanged = true; + } + { + std::pair result + = timers_.insert(Entry(when, timer)); + assert(result.second); (void)result; + } + { + std::pair result + = activeTimers_.insert(ActiveTimer(timer, timer->sequence())); + assert(result.second); (void)result; + } + + assert(timers_.size() == activeTimers_.size()); + return earliestChanged; +} + diff --git a/include/muduo/net/TimerQueue.h b/include/muduo/net/TimerQueue.h new file mode 100644 index 0000000..85da6b7 --- /dev/null +++ b/include/muduo/net/TimerQueue.h @@ -0,0 +1,86 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_TIMERQUEUE_H +#define MUDUO_NET_TIMERQUEUE_H + +#include +#include + +#include "muduo/base/Mutex.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/Channel.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; +class Timer; +class TimerId; + +/// +/// A best efforts timer queue. +/// No guarantee that the callback will be on time. +/// +class TimerQueue : noncopyable +{ + public: + explicit TimerQueue(EventLoop* loop); + ~TimerQueue(); + + /// + /// Schedules the callback to be run at given time, + /// repeats if @c interval > 0.0. + /// + /// Must be thread safe. Usually be called from other threads. + TimerId addTimer(TimerCallback cb, + Timestamp when, + double interval); + + void cancel(TimerId timerId); + + private: + + // FIXME: use unique_ptr instead of raw pointers. + // This requires heterogeneous comparison lookup (N3465) from C++14 + // so that we can find an T* in a set>. + typedef std::pair Entry; + typedef std::set TimerList; + typedef std::pair ActiveTimer; + typedef std::set ActiveTimerSet; + + void addTimerInLoop(Timer* timer); + void cancelInLoop(TimerId timerId); + // called when timerfd alarms + void handleRead(); + // move out all expired timers + std::vector getExpired(Timestamp now); + void reset(const std::vector& expired, Timestamp now); + + bool insert(Timer* timer); + + EventLoop* loop_; + const int timerfd_; + Channel timerfdChannel_; + // Timer list sorted by expiration + TimerList timers_; + + // for cancel() + ActiveTimerSet activeTimers_; + bool callingExpiredTimers_; /* atomic */ + ActiveTimerSet cancelingTimers_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_TIMERQUEUE_H diff --git a/include/muduo/net/ZlibStream.h b/include/muduo/net/ZlibStream.h new file mode 100644 index 0000000..0f143b0 --- /dev/null +++ b/include/muduo/net/ZlibStream.h @@ -0,0 +1,145 @@ +#pragma once + +#include "muduo/base/noncopyable.h" +#include "muduo/net/Buffer.h" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#include + +namespace muduo +{ +namespace net +{ + +// input is zlib compressed data, output uncompressed data +// FIXME: finish this +class ZlibInputStream : noncopyable +{ + public: + explicit ZlibInputStream(Buffer* output) + : output_(output), + zerror_(Z_OK) + { + memZero(&zstream_, sizeof zstream_); + zerror_ = inflateInit(&zstream_); + } + + ~ZlibInputStream() + { + finish(); + } + + bool write(StringPiece buf); + bool write(Buffer* input); + bool finish(); + // inflateEnd(&zstream_); + + private: + int decompress(int flush); + + Buffer* output_; + z_stream zstream_; + int zerror_; +}; + +// input is uncompressed data, output zlib compressed data +class ZlibOutputStream : noncopyable +{ + public: + explicit ZlibOutputStream(Buffer* output) + : output_(output), + zerror_(Z_OK), + bufferSize_(1024) + { + memZero(&zstream_, sizeof zstream_); + zerror_ = deflateInit(&zstream_, Z_DEFAULT_COMPRESSION); + } + + ~ZlibOutputStream() + { + finish(); + } + + // Return last error message or NULL if no error. + const char* zlibErrorMessage() const { return zstream_.msg; } + + int zlibErrorCode() const { return zerror_; } + int64_t inputBytes() const { return zstream_.total_in; } + int64_t outputBytes() const { return zstream_.total_out; } + int internalOutputBufferSize() const { return bufferSize_; } + + bool write(StringPiece buf) + { + if (zerror_ != Z_OK) + return false; + + assert(zstream_.next_in == NULL && zstream_.avail_in == 0); + void* in = const_cast(buf.data()); + zstream_.next_in = static_cast(in); + zstream_.avail_in = buf.size(); + while (zstream_.avail_in > 0 && zerror_ == Z_OK) + { + zerror_ = compress(Z_NO_FLUSH); + } + if (zstream_.avail_in == 0) + { + assert(static_cast(zstream_.next_in) == buf.end()); + zstream_.next_in = NULL; + } + return zerror_ == Z_OK; + } + + // compress input as much as possible, not guarantee consuming all data. + bool write(Buffer* input) + { + if (zerror_ != Z_OK) + return false; + + void* in = const_cast(input->peek()); + zstream_.next_in = static_cast(in); + zstream_.avail_in = static_cast(input->readableBytes()); + if (zstream_.avail_in > 0 && zerror_ == Z_OK) + { + zerror_ = compress(Z_NO_FLUSH); + } + input->retrieve(input->readableBytes() - zstream_.avail_in); + return zerror_ == Z_OK; + } + + bool finish() + { + if (zerror_ != Z_OK) + return false; + + while (zerror_ == Z_OK) + { + zerror_ = compress(Z_FINISH); + } + zerror_ = deflateEnd(&zstream_); + bool ok = zerror_ == Z_OK; + zerror_ = Z_STREAM_END; + return ok; + } + + private: + int compress(int flush) + { + output_->ensureWritableBytes(bufferSize_); + zstream_.next_out = reinterpret_cast(output_->beginWrite()); + zstream_.avail_out = static_cast(output_->writableBytes()); + int error = ::deflate(&zstream_, flush); + output_->hasWritten(output_->writableBytes() - zstream_.avail_out); + if (output_->writableBytes() == 0 && bufferSize_ < 65536) + { + bufferSize_ *= 2; + } + return error; + } + + Buffer* output_; + z_stream zstream_; + int zerror_; + int bufferSize_; +}; + +} // namespace net +} // namespace muduo diff --git a/include/muduo/net/boilerplate.cc b/include/muduo/net/boilerplate.cc new file mode 100644 index 0000000..d0ebe26 --- /dev/null +++ b/include/muduo/net/boilerplate.cc @@ -0,0 +1,15 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/BoilerPlate.h" + +using namespace muduo; +using namespace muduo::net; + + diff --git a/include/muduo/net/boilerplate.h b/include/muduo/net/boilerplate.h new file mode 100644 index 0000000..780661c --- /dev/null +++ b/include/muduo/net/boilerplate.h @@ -0,0 +1,32 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_BOILERPLATE_H +#define MUDUO_NET_BOILERPLATE_H + +#include "muduo/base/noncopyable.h" + +namespace muduo +{ +namespace net +{ + +class BoilerPlate : noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_BOILERPLATE_H diff --git a/include/muduo/net/http/BUILD.bazel b/include/muduo/net/http/BUILD.bazel new file mode 100644 index 0000000..08b98a4 --- /dev/null +++ b/include/muduo/net/http/BUILD.bazel @@ -0,0 +1,9 @@ +cc_library( + name = "http", + srcs = glob(["*.cc"]), + hdrs = glob(["*.h"]), + visibility = ["//visibility:public"], + deps = [ + "//muduo/net", + ], +) diff --git a/include/muduo/net/http/CMakeLists.txt b/include/muduo/net/http/CMakeLists.txt new file mode 100644 index 0000000..51dd981 --- /dev/null +++ b/include/muduo/net/http/CMakeLists.txt @@ -0,0 +1,30 @@ +set(http_SRCS + HttpServer.cc + HttpResponse.cc + HttpContext.cc + ) + +add_library(muduo_http ${http_SRCS}) +target_link_libraries(muduo_http muduo_net) + +install(TARGETS muduo_http DESTINATION lib) +set(HEADERS + HttpContext.h + HttpRequest.h + HttpResponse.h + HttpServer.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/http) + +if(MUDUO_BUILD_EXAMPLES) +add_executable(httpserver_test tests/HttpServer_test.cc) +target_link_libraries(httpserver_test muduo_http) + +if(BOOSTTEST_LIBRARY) +add_executable(httprequest_unittest tests/HttpRequest_unittest.cc) +target_link_libraries(httprequest_unittest muduo_http boost_unit_test_framework) +endif() + +endif() + +# add_subdirectory(tests) diff --git a/include/muduo/net/http/HttpContext.cc b/include/muduo/net/http/HttpContext.cc new file mode 100644 index 0000000..bef3a80 --- /dev/null +++ b/include/muduo/net/http/HttpContext.cc @@ -0,0 +1,118 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Buffer.h" +#include "muduo/net/http/HttpContext.h" + +using namespace muduo; +using namespace muduo::net; + +bool HttpContext::processRequestLine(const char* begin, const char* end) +{ + bool succeed = false; + const char* start = begin; + const char* space = std::find(start, end, ' '); + if (space != end && request_.setMethod(start, space)) + { + start = space+1; + space = std::find(start, end, ' '); + if (space != end) + { + const char* question = std::find(start, space, '?'); + if (question != space) + { + request_.setPath(start, question); + request_.setQuery(question, space); + } + else + { + request_.setPath(start, space); + } + start = space+1; + succeed = end-start == 8 && std::equal(start, end-1, "HTTP/1."); + if (succeed) + { + if (*(end-1) == '1') + { + request_.setVersion(HttpRequest::kHttp11); + } + else if (*(end-1) == '0') + { + request_.setVersion(HttpRequest::kHttp10); + } + else + { + succeed = false; + } + } + } + } + return succeed; +} + +// return false if any error +bool HttpContext::parseRequest(Buffer* buf, Timestamp receiveTime) +{ + bool ok = true; + bool hasMore = true; + while (hasMore) + { + if (state_ == kExpectRequestLine) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + ok = processRequestLine(buf->peek(), crlf); + if (ok) + { + request_.setReceiveTime(receiveTime); + buf->retrieveUntil(crlf + 2); + state_ = kExpectHeaders; + } + else + { + hasMore = false; + } + } + else + { + hasMore = false; + } + } + else if (state_ == kExpectHeaders) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + const char* colon = std::find(buf->peek(), crlf, ':'); + if (colon != crlf) + { + request_.addHeader(buf->peek(), colon, crlf); + } + else + { + // empty line, end of header + // FIXME: + state_ = kGotAll; + hasMore = false; + } + buf->retrieveUntil(crlf + 2); + } + else + { + hasMore = false; + } + } + else if (state_ == kExpectBody) + { + // FIXME: + } + } + return ok; +} diff --git a/include/muduo/net/http/HttpContext.h b/include/muduo/net/http/HttpContext.h new file mode 100644 index 0000000..4beee5c --- /dev/null +++ b/include/muduo/net/http/HttpContext.h @@ -0,0 +1,72 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H +#define MUDUO_NET_HTTP_HTTPCONTEXT_H + +#include "muduo/base/copyable.h" + +#include "muduo/net/http/HttpRequest.h" + +namespace muduo +{ +namespace net +{ + +class Buffer; + +class HttpContext : public muduo::copyable +{ + public: + enum HttpRequestParseState + { + kExpectRequestLine, + kExpectHeaders, + kExpectBody, + kGotAll, + }; + + HttpContext() + : state_(kExpectRequestLine) + { + } + + // default copy-ctor, dtor and assignment are fine + + // return false if any error + bool parseRequest(Buffer* buf, Timestamp receiveTime); + + bool gotAll() const + { return state_ == kGotAll; } + + void reset() + { + state_ = kExpectRequestLine; + HttpRequest dummy; + request_.swap(dummy); + } + + const HttpRequest& request() const + { return request_; } + + HttpRequest& request() + { return request_; } + + private: + bool processRequestLine(const char* begin, const char* end); + + HttpRequestParseState state_; + HttpRequest request_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPCONTEXT_H diff --git a/include/muduo/net/http/HttpRequest.h b/include/muduo/net/http/HttpRequest.h new file mode 100644 index 0000000..9c70c5d --- /dev/null +++ b/include/muduo/net/http/HttpRequest.h @@ -0,0 +1,187 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H +#define MUDUO_NET_HTTP_HTTPREQUEST_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Timestamp.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ +namespace net +{ + +class HttpRequest : public muduo::copyable +{ + public: + enum Method + { + kInvalid, kGet, kPost, kHead, kPut, kDelete + }; + enum Version + { + kUnknown, kHttp10, kHttp11 + }; + + HttpRequest() + : method_(kInvalid), + version_(kUnknown) + { + } + + void setVersion(Version v) + { + version_ = v; + } + + Version getVersion() const + { return version_; } + + bool setMethod(const char* start, const char* end) + { + assert(method_ == kInvalid); + string m(start, end); + if (m == "GET") + { + method_ = kGet; + } + else if (m == "POST") + { + method_ = kPost; + } + else if (m == "HEAD") + { + method_ = kHead; + } + else if (m == "PUT") + { + method_ = kPut; + } + else if (m == "DELETE") + { + method_ = kDelete; + } + else + { + method_ = kInvalid; + } + return method_ != kInvalid; + } + + Method method() const + { return method_; } + + const char* methodString() const + { + const char* result = "UNKNOWN"; + switch(method_) + { + case kGet: + result = "GET"; + break; + case kPost: + result = "POST"; + break; + case kHead: + result = "HEAD"; + break; + case kPut: + result = "PUT"; + break; + case kDelete: + result = "DELETE"; + break; + default: + break; + } + return result; + } + + void setPath(const char* start, const char* end) + { + path_.assign(start, end); + } + + const string& path() const + { return path_; } + + void setQuery(const char* start, const char* end) + { + query_.assign(start, end); + } + + const string& query() const + { return query_; } + + void setReceiveTime(Timestamp t) + { receiveTime_ = t; } + + Timestamp receiveTime() const + { return receiveTime_; } + + void addHeader(const char* start, const char* colon, const char* end) + { + string field(start, colon); + ++colon; + while (colon < end && isspace(*colon)) + { + ++colon; + } + string value(colon, end); + while (!value.empty() && isspace(value[value.size()-1])) + { + value.resize(value.size()-1); + } + headers_[field] = value; + } + + string getHeader(const string& field) const + { + string result; + std::map::const_iterator it = headers_.find(field); + if (it != headers_.end()) + { + result = it->second; + } + return result; + } + + const std::map& headers() const + { return headers_; } + + void swap(HttpRequest& that) + { + std::swap(method_, that.method_); + std::swap(version_, that.version_); + path_.swap(that.path_); + query_.swap(that.query_); + receiveTime_.swap(that.receiveTime_); + headers_.swap(that.headers_); + } + + private: + Method method_; + Version version_; + string path_; + string query_; + Timestamp receiveTime_; + std::map headers_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPREQUEST_H diff --git a/include/muduo/net/http/HttpResponse.cc b/include/muduo/net/http/HttpResponse.cc new file mode 100644 index 0000000..0e2e74d --- /dev/null +++ b/include/muduo/net/http/HttpResponse.cc @@ -0,0 +1,47 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/Buffer.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void HttpResponse::appendToBuffer(Buffer* output) const +{ + char buf[32]; + snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); + output->append(buf); + output->append(statusMessage_); + output->append("\r\n"); + + if (closeConnection_) + { + output->append("Connection: close\r\n"); + } + else + { + snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size()); + output->append(buf); + output->append("Connection: Keep-Alive\r\n"); + } + + for (const auto& header : headers_) + { + output->append(header.first); + output->append(": "); + output->append(header.second); + output->append("\r\n"); + } + + output->append("\r\n"); + output->append(body_); +} diff --git a/include/muduo/net/http/HttpResponse.h b/include/muduo/net/http/HttpResponse.h new file mode 100644 index 0000000..eb3910f --- /dev/null +++ b/include/muduo/net/http/HttpResponse.h @@ -0,0 +1,79 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H +#define MUDUO_NET_HTTP_HTTPRESPONSE_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ +namespace net +{ + +class Buffer; +class HttpResponse : public muduo::copyable +{ + public: + enum HttpStatusCode + { + kUnknown, + k200Ok = 200, + k301MovedPermanently = 301, + k400BadRequest = 400, + k404NotFound = 404, + }; + + explicit HttpResponse(bool close) + : statusCode_(kUnknown), + closeConnection_(close) + { + } + + void setStatusCode(HttpStatusCode code) + { statusCode_ = code; } + + void setStatusMessage(const string& message) + { statusMessage_ = message; } + + void setCloseConnection(bool on) + { closeConnection_ = on; } + + bool closeConnection() const + { return closeConnection_; } + + void setContentType(const string& contentType) + { addHeader("Content-Type", contentType); } + + // FIXME: replace string with StringPiece + void addHeader(const string& key, const string& value) + { headers_[key] = value; } + + void setBody(const string& body) + { body_ = body; } + + void appendToBuffer(Buffer* output) const; + + private: + std::map headers_; + HttpStatusCode statusCode_; + // FIXME: add http version + string statusMessage_; + bool closeConnection_; + string body_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPRESPONSE_H diff --git a/include/muduo/net/http/HttpServer.cc b/include/muduo/net/http/HttpServer.cc new file mode 100644 index 0000000..f7d4678 --- /dev/null +++ b/include/muduo/net/http/HttpServer.cc @@ -0,0 +1,100 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/http/HttpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/http/HttpContext.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +void defaultHttpCallback(const HttpRequest&, HttpResponse* resp) +{ + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); +} + +} // namespace detail +} // namespace net +} // namespace muduo + +HttpServer::HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name, + TcpServer::Option option) + : server_(loop, listenAddr, name, option), + httpCallback_(detail::defaultHttpCallback) +{ + server_.setConnectionCallback( + std::bind(&HttpServer::onConnection, this, _1)); + server_.setMessageCallback( + std::bind(&HttpServer::onMessage, this, _1, _2, _3)); +} + +void HttpServer::start() +{ + LOG_WARN << "HttpServer[" << server_.name() + << "] starts listening on " << server_.ipPort(); + server_.start(); +} + +void HttpServer::onConnection(const TcpConnectionPtr& conn) +{ + if (conn->connected()) + { + conn->setContext(HttpContext()); + } +} + +void HttpServer::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + HttpContext* context = boost::any_cast(conn->getMutableContext()); + + if (!context->parseRequest(buf, receiveTime)) + { + conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); + conn->shutdown(); + } + + if (context->gotAll()) + { + onRequest(conn, context->request()); + context->reset(); + } +} + +void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) +{ + const string& connection = req.getHeader("Connection"); + bool close = connection == "close" || + (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive"); + HttpResponse response(close); + httpCallback_(req, &response); + Buffer buf; + response.appendToBuffer(&buf); + conn->send(&buf); + if (response.closeConnection()) + { + conn->shutdown(); + } +} + diff --git a/include/muduo/net/http/HttpServer.h b/include/muduo/net/http/HttpServer.h new file mode 100644 index 0000000..9609a11 --- /dev/null +++ b/include/muduo/net/http/HttpServer.h @@ -0,0 +1,68 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPSERVER_H +#define MUDUO_NET_HTTP_HTTPSERVER_H + +#include "muduo/net/TcpServer.h" + +namespace muduo +{ +namespace net +{ + +class HttpRequest; +class HttpResponse; + +/// A simple embeddable HTTP server designed for report status of a program. +/// It is not a fully HTTP 1.1 compliant server, but provides minimum features +/// that can communicate with HttpClient and Web browser. +/// It is synchronous, just like Java Servlet. +class HttpServer : noncopyable +{ + public: + typedef std::function HttpCallback; + + HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name, + TcpServer::Option option = TcpServer::kNoReusePort); + + EventLoop* getLoop() const { return server_.getLoop(); } + + /// Not thread safe, callback be registered before calling start(). + void setHttpCallback(const HttpCallback& cb) + { + httpCallback_ = cb; + } + + void setThreadNum(int numThreads) + { + server_.setThreadNum(numThreads); + } + + void start(); + + private: + void onConnection(const TcpConnectionPtr& conn); + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + void onRequest(const TcpConnectionPtr&, const HttpRequest&); + + TcpServer server_; + HttpCallback httpCallback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPSERVER_H diff --git a/include/muduo/net/http/tests/HttpRequest_unittest.cc b/include/muduo/net/http/tests/HttpRequest_unittest.cc new file mode 100644 index 0000000..cb89305 --- /dev/null +++ b/include/muduo/net/http/tests/HttpRequest_unittest.cc @@ -0,0 +1,79 @@ +#include "muduo/net/http/HttpContext.h" +#include "muduo/net/Buffer.h" + +//#define BOOST_TEST_MODULE BufferTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::Timestamp; +using muduo::net::Buffer; +using muduo::net::HttpContext; +using muduo::net::HttpRequest; + +BOOST_AUTO_TEST_CASE(testParseRequestAllInOne) +{ + HttpContext context; + Buffer input; + input.append("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "\r\n"); + + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); +} + +BOOST_AUTO_TEST_CASE(testParseRequestInTwoPieces) +{ + string all("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "\r\n"); + + for (size_t sz1 = 0; sz1 < all.size(); ++sz1) + { + HttpContext context; + Buffer input; + input.append(all.c_str(), sz1); + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(!context.gotAll()); + + size_t sz2 = all.size() - sz1; + input.append(all.c_str() + sz1, sz2); + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); + } +} + +BOOST_AUTO_TEST_CASE(testParseRequestEmptyHeaderValue) +{ + HttpContext context; + Buffer input; + input.append("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "User-Agent:\r\n" + "Accept-Encoding: \r\n" + "\r\n"); + + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); + BOOST_CHECK_EQUAL(request.getHeader("Accept-Encoding"), string("")); +} diff --git a/include/muduo/net/http/tests/HttpServer_test.cc b/include/muduo/net/http/tests/HttpServer_test.cc new file mode 100644 index 0000000..0ec38fb --- /dev/null +++ b/include/muduo/net/http/tests/HttpServer_test.cc @@ -0,0 +1,150 @@ +#include "muduo/net/http/HttpServer.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Logging.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +extern char favicon[555]; +bool benchmark = false; + +void onRequest(const HttpRequest& req, HttpResponse* resp) +{ + std::cout << "Headers " << req.methodString() << " " << req.path() << std::endl; + if (!benchmark) + { + const std::map& headers = req.headers(); + for (const auto& header : headers) + { + std::cout << header.first << ": " << header.second << std::endl; + } + } + + if (req.path() == "/") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/html"); + resp->addHeader("Server", "Muduo"); + string now = Timestamp::now().toFormattedString(); + resp->setBody("This is title" + "

Hello

Now is " + now + + ""); + } + else if (req.path() == "/favicon.ico") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("image/png"); + resp->setBody(string(favicon, sizeof favicon)); + } + else if (req.path() == "/hello") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->addHeader("Server", "Muduo"); + resp->setBody("hello, world!\n"); + } + else + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); + } +} + +int main(int argc, char* argv[]) +{ + int numThreads = 0; + if (argc > 1) + { + benchmark = true; + Logger::setLogLevel(Logger::WARN); + numThreads = atoi(argv[1]); + } + EventLoop loop; + HttpServer server(&loop, InetAddress(8000), "dummy"); + server.setHttpCallback(onRequest); + server.setThreadNum(numThreads); + server.start(); + loop.loop(); +} + +char favicon[555] = { + '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA', + '\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R', + '\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10', + '\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF', + 'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X', + 't', 'S', 'o', 'f', 't', 'w', 'a', 'r', + 'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20', + 'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a', + 'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0', + '\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA', + '\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86', + '\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm', + '\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16', + 'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8', + 'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0', + 'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4', + 'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1', + 'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB', + 'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F', + 'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v', + 'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8', + '\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5', + '\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC', + '\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA', + '\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F', + '\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r', + '9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6', + '\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T', + '\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3', + 'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R', + '\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x', + '\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0', + '\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9', + 'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11', + '\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5', + '3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4', + '\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98', + '\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3', + '\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C', + '\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB', + '\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9', + 'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6', + '\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C', + '\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f', + 'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9', + 'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F', + '\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22', + '\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15', + '\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j', + '\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F', + 'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40', + '\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A', + '\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE', + '\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD', + '\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0', + '\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB', + '\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2', + '\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4', + '\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A', + '\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91', + '\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7', + 'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N', + 'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E', + '\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u', + '\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB', + '\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF', + '\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K', + '\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0', + '\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE', + 'B', '\x60', '\x82', +}; diff --git a/include/muduo/net/inspect/BUILD.bazel b/include/muduo/net/inspect/BUILD.bazel new file mode 100644 index 0000000..0592e50 --- /dev/null +++ b/include/muduo/net/inspect/BUILD.bazel @@ -0,0 +1,9 @@ +cc_library( + name = "inspect", + srcs = glob(["*.cc"]), + hdrs = glob(["*.h"]), + visibility = ["//visibility:public"], + deps = [ + "//muduo/net/http", + ], +) diff --git a/include/muduo/net/inspect/CMakeLists.txt b/include/muduo/net/inspect/CMakeLists.txt new file mode 100644 index 0000000..1ce908f --- /dev/null +++ b/include/muduo/net/inspect/CMakeLists.txt @@ -0,0 +1,26 @@ +set(inspect_SRCS + Inspector.cc + PerformanceInspector.cc + ProcessInspector.cc + SystemInspector.cc + ) + +add_library(muduo_inspect ${inspect_SRCS}) +target_link_libraries(muduo_inspect muduo_http) + +if(TCMALLOC_INCLUDE_DIR AND TCMALLOC_LIBRARY) + set_target_properties(muduo_inspect PROPERTIES COMPILE_FLAGS "-DHAVE_TCMALLOC") + target_link_libraries(muduo_inspect tcmalloc_and_profiler) +endif() + +install(TARGETS muduo_inspect DESTINATION lib) +set(HEADERS + Inspector.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/inspect) + +if(MUDUO_BUILD_EXAMPLES) +add_executable(inspector_test tests/Inspector_test.cc) +target_link_libraries(inspector_test muduo_inspect) +endif() + diff --git a/include/muduo/net/inspect/Inspector.cc b/include/muduo/net/inspect/Inspector.cc new file mode 100644 index 0000000..894abd3 --- /dev/null +++ b/include/muduo/net/inspect/Inspector.cc @@ -0,0 +1,383 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/Inspector.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/inspect/ProcessInspector.h" +#include "muduo/net/inspect/PerformanceInspector.h" +#include "muduo/net/inspect/SystemInspector.h" + +//#include +//#include +//#include +//#include +//#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ +Inspector* g_globalInspector = 0; + +// Looks buggy +std::vector split(const string& str) +{ + std::vector result; + size_t start = 0; + size_t pos = str.find('/'); + while (pos != string::npos) + { + if (pos > start) + { + result.push_back(str.substr(start, pos-start)); + } + start = pos+1; + pos = str.find('/', start); + } + + if (start < str.length()) + { + result.push_back(str.substr(start)); + } + + return result; +} + +} // namespace + +extern char favicon[1743]; + +Inspector::Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name) + : server_(loop, httpAddr, "Inspector:"+name), + processInspector_(new ProcessInspector), + systemInspector_(new SystemInspector) +{ + assert(CurrentThread::isMainThread()); + assert(g_globalInspector == 0); + g_globalInspector = this; + server_.setHttpCallback(std::bind(&Inspector::onRequest, this, _1, _2)); + processInspector_->registerCommands(this); + systemInspector_->registerCommands(this); +#ifdef HAVE_TCMALLOC + performanceInspector_.reset(new PerformanceInspector); + performanceInspector_->registerCommands(this); +#endif + loop->runAfter(0, std::bind(&Inspector::start, this)); // little race condition +} + +Inspector::~Inspector() +{ + assert(CurrentThread::isMainThread()); + g_globalInspector = NULL; +} + +void Inspector::add(const string& module, + const string& command, + const Callback& cb, + const string& help) +{ + MutexLockGuard lock(mutex_); + modules_[module][command] = cb; + helps_[module][command] = help; +} + +void Inspector::remove(const string& module, const string& command) +{ + MutexLockGuard lock(mutex_); + std::map::iterator it = modules_.find(module); + if (it != modules_.end()) + { + it->second.erase(command); + helps_[module].erase(command); + } +} + +void Inspector::start() +{ + server_.start(); +} + +void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) +{ + if (req.path() == "/") + { + string result; + MutexLockGuard lock(mutex_); + for (std::map::const_iterator helpListI = helps_.begin(); + helpListI != helps_.end(); + ++helpListI) + { + const HelpList& list = helpListI->second; + for (const auto& it : list) + { + result += "/"; + result += helpListI->first; + result += "/"; + result += it.first; + size_t len = helpListI->first.size() + it.first.size(); + result += string(len >= 25 ? 1 : 25 - len, ' '); + result += it.second; + result += "\n"; + } + } + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->setBody(result); + } + else + { + std::vector result = split(req.path()); + // boost::split(result, req.path(), boost::is_any_of("/")); + //std::copy(result.begin(), result.end(), std::ostream_iterator(std::cout, ", ")); + //std::cout << "\n"; + bool ok = false; + if (result.size() == 0) + { + LOG_DEBUG << req.path(); + } + else if (result.size() == 1) + { + string module = result[0]; + if (module == "favicon.ico") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("image/png"); + resp->setBody(string(favicon, sizeof favicon)); + + ok = true; + } + else + { + LOG_ERROR << "Unimplemented " << module; + } + } + else + { + string module = result[0]; + MutexLockGuard lock(mutex_); + std::map::const_iterator commListI = modules_.find(module); + if (commListI != modules_.end()) + { + string command = result[1]; + const CommandList& commList = commListI->second; + CommandList::const_iterator it = commList.find(command); + if (it != commList.end()) + { + ArgList args(result.begin()+2, result.end()); + if (it->second) + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + const Callback& cb = it->second; + resp->setBody(cb(req.method(), args)); + ok = true; + } + } + } + + } + + if (!ok) + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + } + //resp->setCloseConnection(true); + } +} + +char favicon[1743] = +{ + '\x89', '\x50', '\x4e', '\x47', '\x0d', '\x0a', '\x1a', '\x0a', '\x00', '\x00', + '\x00', '\x0d', '\x49', '\x48', '\x44', '\x52', '\x00', '\x00', '\x00', '\x10', + '\x00', '\x00', '\x00', '\x10', '\x08', '\x06', '\x00', '\x00', '\x00', '\x1f', + '\xf3', '\xff', '\x61', '\x00', '\x00', '\x00', '\x04', '\x73', '\x42', '\x49', + '\x54', '\x08', '\x08', '\x08', '\x08', '\x7c', '\x08', '\x64', '\x88', '\x00', + '\x00', '\x00', '\x09', '\x70', '\x48', '\x59', '\x73', '\x00', '\x00', '\x0b', + '\x12', '\x00', '\x00', '\x0b', '\x12', '\x01', '\xd2', '\xdd', '\x7e', '\xfc', + '\x00', '\x00', '\x00', '\x1c', '\x74', '\x45', '\x58', '\x74', '\x53', '\x6f', + '\x66', '\x74', '\x77', '\x61', '\x72', '\x65', '\x00', '\x41', '\x64', '\x6f', + '\x62', '\x65', '\x20', '\x46', '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', + '\x6b', '\x73', '\x20', '\x43', '\x53', '\x33', '\x98', '\xd6', '\x46', '\x03', + '\x00', '\x00', '\x00', '\x15', '\x74', '\x45', '\x58', '\x74', '\x43', '\x72', + '\x65', '\x61', '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x54', '\x69', '\x6d', + '\x65', '\x00', '\x32', '\x2f', '\x31', '\x37', '\x2f', '\x30', '\x38', '\x20', + '\x9c', '\xaa', '\x58', '\x00', '\x00', '\x04', '\x11', '\x74', '\x45', '\x58', + '\x74', '\x58', '\x4d', '\x4c', '\x3a', '\x63', '\x6f', '\x6d', '\x2e', '\x61', + '\x64', '\x6f', '\x62', '\x65', '\x2e', '\x78', '\x6d', '\x70', '\x00', '\x3c', + '\x3f', '\x78', '\x70', '\x61', '\x63', '\x6b', '\x65', '\x74', '\x20', '\x62', + '\x65', '\x67', '\x69', '\x6e', '\x3d', '\x22', '\x20', '\x20', '\x20', '\x22', + '\x20', '\x69', '\x64', '\x3d', '\x22', '\x57', '\x35', '\x4d', '\x30', '\x4d', + '\x70', '\x43', '\x65', '\x68', '\x69', '\x48', '\x7a', '\x72', '\x65', '\x53', + '\x7a', '\x4e', '\x54', '\x63', '\x7a', '\x6b', '\x63', '\x39', '\x64', '\x22', + '\x3f', '\x3e', '\x0a', '\x3c', '\x78', '\x3a', '\x78', '\x6d', '\x70', '\x6d', + '\x65', '\x74', '\x61', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', + '\x78', '\x3d', '\x22', '\x61', '\x64', '\x6f', '\x62', '\x65', '\x3a', '\x6e', + '\x73', '\x3a', '\x6d', '\x65', '\x74', '\x61', '\x2f', '\x22', '\x20', '\x78', + '\x3a', '\x78', '\x6d', '\x70', '\x74', '\x6b', '\x3d', '\x22', '\x41', '\x64', + '\x6f', '\x62', '\x65', '\x20', '\x58', '\x4d', '\x50', '\x20', '\x43', '\x6f', + '\x72', '\x65', '\x20', '\x34', '\x2e', '\x31', '\x2d', '\x63', '\x30', '\x33', + '\x34', '\x20', '\x34', '\x36', '\x2e', '\x32', '\x37', '\x32', '\x39', '\x37', + '\x36', '\x2c', '\x20', '\x53', '\x61', '\x74', '\x20', '\x4a', '\x61', '\x6e', + '\x20', '\x32', '\x37', '\x20', '\x32', '\x30', '\x30', '\x37', '\x20', '\x32', + '\x32', '\x3a', '\x31', '\x31', '\x3a', '\x34', '\x31', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x22', '\x3e', '\x0a', '\x20', '\x20', + '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x52', '\x44', '\x46', '\x20', + '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x72', '\x64', '\x66', '\x3d', + '\x22', '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x77', '\x77', + '\x77', '\x2e', '\x77', '\x33', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x31', + '\x39', '\x39', '\x39', '\x2f', '\x30', '\x32', '\x2f', '\x32', '\x32', '\x2d', + '\x72', '\x64', '\x66', '\x2d', '\x73', '\x79', '\x6e', '\x74', '\x61', '\x78', + '\x2d', '\x6e', '\x73', '\x23', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x44', '\x65', + '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', '\x20', + '\x72', '\x64', '\x66', '\x3a', '\x61', '\x62', '\x6f', '\x75', '\x74', '\x3d', + '\x22', '\x22', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', + '\x3a', '\x78', '\x61', '\x70', '\x3d', '\x22', '\x68', '\x74', '\x74', '\x70', + '\x3a', '\x2f', '\x2f', '\x6e', '\x73', '\x2e', '\x61', '\x64', '\x6f', '\x62', + '\x65', '\x2e', '\x63', '\x6f', '\x6d', '\x2f', '\x78', '\x61', '\x70', '\x2f', + '\x31', '\x2e', '\x30', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', + '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', + '\x6f', '\x6c', '\x3e', '\x41', '\x64', '\x6f', '\x62', '\x65', '\x20', '\x46', + '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', '\x6b', '\x73', '\x20', '\x43', + '\x53', '\x33', '\x3c', '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', + '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', '\x6f', '\x6c', '\x3e', + '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', + '\x65', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', '\x30', '\x30', '\x38', + '\x2d', '\x30', '\x32', '\x2d', '\x31', '\x37', '\x54', '\x30', '\x32', '\x3a', + '\x33', '\x36', '\x3a', '\x34', '\x35', '\x5a', '\x3c', '\x2f', '\x78', '\x61', + '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x65', '\x44', '\x61', + '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', + '\x64', '\x69', '\x66', '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', + '\x30', '\x30', '\x38', '\x2d', '\x30', '\x33', '\x2d', '\x32', '\x34', '\x54', + '\x31', '\x39', '\x3a', '\x30', '\x30', '\x3a', '\x34', '\x32', '\x5a', '\x3c', + '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', '\x64', '\x69', '\x66', + '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', + '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', + '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x72', + '\x64', '\x66', '\x3a', '\x44', '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', + '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x72', '\x64', '\x66', '\x3a', '\x61', + '\x62', '\x6f', '\x75', '\x74', '\x3d', '\x22', '\x22', '\x0a', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x64', '\x63', '\x3d', '\x22', + '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x70', '\x75', '\x72', + '\x6c', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x64', '\x63', '\x2f', '\x65', + '\x6c', '\x65', '\x6d', '\x65', '\x6e', '\x74', '\x73', '\x2f', '\x31', '\x2e', + '\x31', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x3c', '\x64', '\x63', '\x3a', '\x66', '\x6f', + '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x69', '\x6d', '\x61', '\x67', '\x65', + '\x2f', '\x70', '\x6e', '\x67', '\x3c', '\x2f', '\x64', '\x63', '\x3a', '\x66', + '\x6f', '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', + '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', + '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', + '\x3a', '\x52', '\x44', '\x46', '\x3e', '\x0a', '\x3c', '\x2f', '\x78', '\x3a', + '\x78', '\x6d', '\x70', '\x6d', '\x65', '\x74', '\x61', '\x3e', '\x0a', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x0a', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x35', '\x1d', '\x52', '\x64', '\x00', '\x00', '\x02', '\x0b', + '\x49', '\x44', '\x41', '\x54', '\x38', '\x8d', '\xa5', '\x93', '\x41', '\x6b', + '\x1a', '\x41', '\x18', '\x86', '\x9f', '\x89', '\x06', '\x23', '\x2e', '\x74', + '\xf5', '\x20', '\x4a', '\x0e', '\x6b', '\x20', '\xe4', '\xe2', '\xa5', '\x78', + '\xc8', '\xa1', '\x78', '\x89', '\x82', '\x17', '\x85', '\x82', '\x82', '\x3d', + '\x26', '\x62', '\x58', '\x72', '\xcd', '\x4f', '\xf1', '\x18', '\x4b', '\x1b', + '\x2f', '\xa5', '\x32', '\xe0', '\xb5', '\x9e', '\x35', '\x1a', '\x58', '\x2f', + '\xe9', '\x0f', '\xe8', '\x65', '\x6d', '\x84', '\xa2', '\x84', '\x2c', '\x0a', + '\x6b', '\x58', '\x62', '\xa7', '\x87', '\x68', '\x68', '\x13', '\xa1', '\xa5', + '\x79', '\xe1', '\x3b', '\x0c', '\xc3', '\xfb', '\xcc', '\x37', '\xef', '\x7c', + '\x23', '\x94', '\x52', '\xbc', '\x44', '\x7e', '\x00', '\x21', '\x04', '\x00', + '\xad', '\x56', '\xcb', '\x18', '\x8f', '\xc7', '\x0d', '\xdb', '\xb6', '\xd3', + '\x8e', '\xe3', '\xf8', '\x83', '\xc1', '\xa0', '\x8a', '\xc7', '\xe3', '\x3f', + '\x12', '\x89', '\x44', '\xb9', '\x5c', '\x2e', '\xf7', '\x56', '\xa6', '\xdf', + '\x0f', '\x15', '\x4a', '\x29', '\x84', '\x10', '\x34', '\x9b', '\xcd', '\x77', + '\x96', '\x65', '\x7d', '\x36', '\x0c', '\x43', '\xe4', '\x72', '\x39', '\xe2', + '\xf1', '\x38', '\xb7', '\xb7', '\xb7', '\xf4', '\xfb', '\x7d', '\x06', '\x83', + '\x01', '\xa9', '\x54', '\xea', '\x43', '\xa5', '\x52', '\x39', '\x7e', '\x0a', + '\x40', '\x29', '\x45', '\xab', '\xd5', '\x32', '\x4e', '\x4f', '\x4f', '\x7f', + '\x4a', '\x29', '\xd5', '\xdd', '\xdd', '\xdd', '\xb3', '\xea', '\xf5', '\x7a', + '\xea', '\xe4', '\xe4', '\x44', '\x49', '\x29', '\xd3', '\x2b', '\xcf', '\xaa', + '\x36', '\x00', '\xc6', '\xe3', '\x71', '\x63', '\x67', '\x67', '\x47', '\xe4', + '\xf3', '\x79', '\x00', '\x3c', '\xcf', '\xa3', '\x50', '\x28', '\xe0', '\xba', + '\x2e', '\x9e', '\xe7', '\x91', '\x4a', '\xa5', '\xd8', '\xdb', '\xdb', '\x63', + '\x34', '\x1a', '\x7d', '\x7c', '\x9a', '\xc1', '\x06', '\x80', '\x6d', '\xdb', + '\xe9', '\x6c', '\x36', '\x8b', '\xcf', '\xe7', '\xc3', '\xf3', '\x3c', '\x5c', + '\xd7', '\x05', '\x60', '\x36', '\x9b', '\xe1', '\xba', '\x2e', '\x8b', '\xc5', + '\x82', '\x4c', '\x26', '\x83', '\x6d', '\xdb', '\xbb', '\x6b', '\x43', '\x74', + '\x1c', '\xc7', '\x1f', '\x8b', '\xc5', '\x00', '\x28', '\x16', '\x8b', '\x8f', + '\x9b', '\xd5', '\x6a', '\x15', '\x00', '\x29', '\x25', '\x9a', '\xa6', '\x31', + '\x9f', '\xcf', '\xc5', '\x5a', '\xc0', '\xd6', '\xd6', '\x96', '\x9a', '\x4c', + '\x26', '\x22', '\x14', '\x0a', '\x21', '\xa5', '\x64', '\x36', '\x9b', '\x51', + '\xad', '\x56', '\xa9', '\xd5', '\x6a', '\x68', '\x9a', '\x06', '\xc0', '\xf5', + '\xf5', '\x35', '\xba', '\xae', '\xdf', '\xaf', '\xbd', '\x82', '\x61', '\x18', + '\xdf', '\x2c', '\xcb', '\x7a', '\x20', '\xfa', '\xfd', '\x04', '\x02', '\x01', + '\x00', '\x34', '\x4d', '\x23', '\x10', '\x08', '\xb0', '\x58', '\x2c', '\xe8', + '\x76', '\xbb', '\x24', '\x12', '\x89', '\x8b', '\xb5', '\x1d', '\x6c', '\x6f', + '\x6f', '\x1f', '\x75', '\x3a', '\x9d', '\x7e', '\x38', '\x1c', '\x26', '\x97', + '\xcb', '\x21', '\x84', '\x40', '\x4a', '\x09', '\xc0', '\xe6', '\xe6', '\x26', + '\xed', '\x76', '\x9b', '\xc9', '\x64', '\xa2', '\xa6', '\xd3', '\xe9', '\x27', + '\x78', '\x98', '\x9b', '\xd5', '\x53', '\x3e', '\xce', '\xc1', '\xf9', '\xf9', + '\xf9', '\xfb', '\xc1', '\x60', '\x70', '\x9c', '\x4c', '\x26', '\xd9', '\xdf', + '\xdf', '\x27', '\x12', '\x89', '\x30', '\x1c', '\x0e', '\xb9', '\xbc', '\xbc', + '\xe4', '\xe6', '\xe6', '\x46', '\xf9', '\x7c', '\xbe', '\x2f', '\xd3', '\xe9', + '\x34', '\x0f', '\x34', '\xea', '\xf5', '\x7a', '\xe5', '\x19', '\x60', '\x19', + '\xd6', '\x9b', '\xd1', '\x68', '\xd4', '\x18', '\x0e', '\x87', '\xbb', '\xf3', + '\xf9', '\x5c', '\xe8', '\xba', '\x7e', '\x6f', '\x18', '\xc6', '\x45', '\x34', + '\x1a', '\x3d', '\x2c', '\x95', '\x4a', '\xdf', '\x4d', '\xd3', '\xbc', '\x02', + '\x5e', '\x03', '\x5f', '\x81', '\x83', '\xb3', '\xb3', '\x33', '\xe7', '\x0f', + '\xc0', '\xdf', '\x64', '\x9a', '\xa6', '\xb1', '\x34', '\xeb', '\x80', '\x03', + '\x1c', '\x6c', '\xfc', '\x93', '\x73', '\xa9', '\x7a', '\xbd', '\x6e', '\x03', + '\x47', '\xcb', '\xa5', '\x0e', '\xbc', '\xe2', '\x7f', '\x7e', '\xa3', '\x69', + '\x9a', '\x87', '\xa6', '\x69', '\xbe', '\x55', '\x4a', '\x3d', '\x64', '\xf0', + '\x12', '\xfd', '\x02', '\x0d', '\x53', '\x06', '\x24', '\x88', '\x3f', '\xe1', + '\x69', '\x00', '\x00', '\x00', '\x00', '\x49', '\x45', '\x4e', '\x44', '\xae', + '\x42', '\x60', '\x82', +}; diff --git a/include/muduo/net/inspect/Inspector.h b/include/muduo/net/inspect/Inspector.h new file mode 100644 index 0000000..09041d1 --- /dev/null +++ b/include/muduo/net/inspect/Inspector.h @@ -0,0 +1,67 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_INSPECT_INSPECTOR_H +#define MUDUO_NET_INSPECT_INSPECTOR_H + +#include "muduo/base/Mutex.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpServer.h" + +#include + +namespace muduo +{ +namespace net +{ + +class ProcessInspector; +class PerformanceInspector; +class SystemInspector; + +// An internal inspector of the running process, usually a singleton. +// Better to run in a seperated thread, as some method may block for seconds +class Inspector : noncopyable +{ + public: + typedef std::vector ArgList; + typedef std::function Callback; + Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name); + ~Inspector(); + + /// Add a Callback for handling the special uri : /mudule/command + void add(const string& module, + const string& command, + const Callback& cb, + const string& help); + void remove(const string& module, const string& command); + + private: + typedef std::map CommandList; + typedef std::map HelpList; + + void start(); + void onRequest(const HttpRequest& req, HttpResponse* resp); + + HttpServer server_; + std::unique_ptr processInspector_; + std::unique_ptr performanceInspector_; + std::unique_ptr systemInspector_; + MutexLock mutex_; + std::map modules_ GUARDED_BY(mutex_); + std::map helps_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_INSPECTOR_H diff --git a/include/muduo/net/inspect/PerformanceInspector.cc b/include/muduo/net/inspect/PerformanceInspector.cc new file mode 100644 index 0000000..a0fb9e9 --- /dev/null +++ b/include/muduo/net/inspect/PerformanceInspector.cc @@ -0,0 +1,106 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/PerformanceInspector.h" +#include "muduo/base/FileUtil.h" +#include "muduo/base/LogStream.h" +#include "muduo/base/ProcessInfo.h" + +#include + +#ifdef HAVE_TCMALLOC +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void PerformanceInspector::registerCommands(Inspector* ins) +{ + ins->add("pprof", "heap", PerformanceInspector::heap, "get heap information"); + ins->add("pprof", "growth", PerformanceInspector::growth, "get heap growth information"); + ins->add("pprof", "profile", PerformanceInspector::profile, + "get cpu profiling information. CAUTION: blocking thread for 30 seconds!"); + ins->add("pprof", "cmdline", PerformanceInspector::cmdline, "get command line"); + ins->add("pprof", "memstats", PerformanceInspector::memstats, "get memory stats"); + ins->add("pprof", "memhistogram", PerformanceInspector::memhistogram, "get memory histogram"); + ins->add("pprof", "releasefreememory", PerformanceInspector::releaseFreeMemory, "release free memory"); +} + +string PerformanceInspector::heap(HttpRequest::Method, const Inspector::ArgList&) +{ + std::string result; + MallocExtension::instance()->GetHeapSample(&result); + return string(result.data(), result.size()); +} + +string PerformanceInspector::growth(HttpRequest::Method, const Inspector::ArgList&) +{ + std::string result; + MallocExtension::instance()->GetHeapGrowthStacks(&result); + return string(result.data(), result.size()); +} + +string PerformanceInspector::profile(HttpRequest::Method, const Inspector::ArgList&) +{ + string filename = "/tmp/" + ProcessInfo::procname(); + filename += "."; + filename += ProcessInfo::pidString(); + filename += "."; + filename += Timestamp::now().toString(); + filename += ".profile"; + + string profile; + if (ProfilerStart(filename.c_str())) + { + // FIXME: async + CurrentThread::sleepUsec(30 * 1000 * 1000); + ProfilerStop(); + FileUtil::readFile(filename, 1024*1024, &profile, NULL, NULL); + ::unlink(filename.c_str()); + } + return profile; +} + +string PerformanceInspector::cmdline(HttpRequest::Method, const Inspector::ArgList&) +{ + return ""; +} + +string PerformanceInspector::memstats(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[1024*64]; + MallocExtension::instance()->GetStats(buf, sizeof buf); + return buf; +} + +string PerformanceInspector::memhistogram(HttpRequest::Method, const Inspector::ArgList&) +{ + int blocks = 0; + size_t total = 0; + int histogram[kMallocHistogramSize] = { 0, }; + + MallocExtension::instance()->MallocMemoryStats(&blocks, &total, histogram); + LogStream s; + s << "blocks " << blocks << "\ntotal " << total << "\n"; + for (int i = 0; i < kMallocHistogramSize; ++i) + s << i << " " << histogram[i] << "\n"; + return s.buffer().toString(); +} + +string PerformanceInspector::releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[256]; + snprintf(buf, sizeof buf, "memory release rate: %f\nAll free memory released.\n", + MallocExtension::instance()->GetMemoryReleaseRate()); + MallocExtension::instance()->ReleaseFreeMemory(); + return buf; +} + +#endif diff --git a/include/muduo/net/inspect/PerformanceInspector.h b/include/muduo/net/inspect/PerformanceInspector.h new file mode 100644 index 0000000..2416824 --- /dev/null +++ b/include/muduo/net/inspect/PerformanceInspector.h @@ -0,0 +1,40 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H +#define MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class PerformanceInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string heap(HttpRequest::Method, const Inspector::ArgList&); + static string growth(HttpRequest::Method, const Inspector::ArgList&); + static string profile(HttpRequest::Method, const Inspector::ArgList&); + static string cmdline(HttpRequest::Method, const Inspector::ArgList&); + static string memstats(HttpRequest::Method, const Inspector::ArgList&); + static string memhistogram(HttpRequest::Method, const Inspector::ArgList&); + static string releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&); + + static string symbol(HttpRequest::Method, const Inspector::ArgList&); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H diff --git a/include/muduo/net/inspect/ProcessInspector.cc b/include/muduo/net/inspect/ProcessInspector.cc new file mode 100644 index 0000000..d89f0ce --- /dev/null +++ b/include/muduo/net/inspect/ProcessInspector.cc @@ -0,0 +1,239 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/ProcessInspector.h" +#include "muduo/base/FileUtil.h" +#include "muduo/base/ProcessInfo.h" +#include +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace inspect +{ + +string uptime(Timestamp now, Timestamp start, bool showMicroseconds) +{ + char buf[256]; + int64_t age = now.microSecondsSinceEpoch() - start.microSecondsSinceEpoch(); + int seconds = static_cast(age / Timestamp::kMicroSecondsPerSecond); + int days = seconds/86400; + int hours = (seconds % 86400) / 3600; + int minutes = (seconds % 3600) / 60; + if (showMicroseconds) + { + int microseconds = static_cast(age % Timestamp::kMicroSecondsPerSecond); + snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d.%06d", + days, hours, minutes, seconds % 60, microseconds); + } + else + { + snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d", + days, hours, minutes, seconds % 60); + } + return buf; +} + +long getLong(const string& procStatus, const char* key) +{ + long result = 0; + size_t pos = procStatus.find(key); + if (pos != string::npos) + { + result = ::atol(procStatus.c_str() + pos + strlen(key)); + } + return result; +} + +string getProcessName(const string& procStatus) +{ + string result; + size_t pos = procStatus.find("Name:"); + if (pos != string::npos) + { + pos += strlen("Name:"); + while (procStatus[pos] == '\t') + ++pos; + size_t eol = pos; + while (procStatus[eol] != '\n') + ++eol; + result = procStatus.substr(pos, eol-pos); + } + return result; +} + +StringPiece next(StringPiece data) +{ + const char* sp = static_cast(::memchr(data.data(), ' ', data.size())); + if (sp) + { + data.remove_prefix(static_cast(sp+1-data.begin())); + return data; + } + return ""; +} + +ProcessInfo::CpuTime getCpuTime(StringPiece data) +{ + ProcessInfo::CpuTime t; + + for (int i = 0; i < 10; ++i) + { + data = next(data); + } + long utime = strtol(data.data(), NULL, 10); + data = next(data); + long stime = strtol(data.data(), NULL, 10); + const double hz = static_cast(ProcessInfo::clockTicksPerSecond()); + t.userSeconds = static_cast(utime) / hz; + t.systemSeconds = static_cast(stime) / hz; + return t; +} + +int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); + +int stringPrintf(string* out, const char* fmt, ...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + int ret = vsnprintf(buf, sizeof buf, fmt, args); + va_end(args); + out->append(buf); + return ret; +} + +} // namespace inspect +} // namespace muduo + +using namespace muduo::inspect; + +string ProcessInspector::username_ = ProcessInfo::username(); + +void ProcessInspector::registerCommands(Inspector* ins) +{ + ins->add("proc", "overview", ProcessInspector::overview, "print basic overview"); + ins->add("proc", "pid", ProcessInspector::pid, "print pid"); + ins->add("proc", "status", ProcessInspector::procStatus, "print /proc/self/status"); + // ins->add("proc", "opened_files", ProcessInspector::openedFiles, "count /proc/self/fd"); + ins->add("proc", "threads", ProcessInspector::threads, "list /proc/self/task"); +} + +string ProcessInspector::overview(HttpRequest::Method, const Inspector::ArgList&) +{ + string result; + result.reserve(1024); + Timestamp now = Timestamp::now(); + result += "Page generated at "; + result += now.toFormattedString(); + result += " (UTC)\nStarted at "; + result += ProcessInfo::startTime().toFormattedString(); + result += " (UTC), up for "; + result += uptime(now, ProcessInfo::startTime(), true/* show microseconds */); + result += "\n"; + + string procStatus = ProcessInfo::procStatus(); + result += getProcessName(procStatus); + result += " ("; + result += ProcessInfo::exePath(); + result += ") running as "; + result += username_; + result += " on "; + result += ProcessInfo::hostname(); // cache ? + result += "\n"; + + if (ProcessInfo::isDebugBuild()) + { + result += "WARNING: debug build!\n"; + } + + stringPrintf(&result, "pid %d, num of threads %ld, bits %zd\n", + ProcessInfo::pid(), getLong(procStatus, "Threads:"), CHAR_BIT * sizeof(void*)); + + result += "Virtual memory: "; + stringPrintf(&result, "%.3f MiB, ", + static_cast(getLong(procStatus, "VmSize:")) / 1024.0); + + result += "RSS memory: "; + stringPrintf(&result, "%.3f MiB\n", + static_cast(getLong(procStatus, "VmRSS:")) / 1024.0); + + // FIXME: VmData: + + stringPrintf(&result, "Opened files: %d, limit: %d\n", + ProcessInfo::openedFiles(), ProcessInfo::maxOpenFiles()); + + // string procStat = ProcessInfo::procStat(); + + /* + stringPrintf(&result, "ppid %ld\n", getStatField(procStat, 0)); + stringPrintf(&result, "pgid %ld\n", getStatField(procStat, 1)); + */ + + ProcessInfo::CpuTime t = ProcessInfo::cpuTime(); + stringPrintf(&result, "User time: %12.3fs\nSys time: %12.3fs\n", + t.userSeconds, t.systemSeconds); + + // FIXME: add context switches + + return result; +} + +string ProcessInspector::pid(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::pid()); + return buf; +} + +string ProcessInspector::procStatus(HttpRequest::Method, const Inspector::ArgList&) +{ + return ProcessInfo::procStatus(); +} + +string ProcessInspector::openedFiles(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::openedFiles()); + return buf; +} + +string ProcessInspector::threads(HttpRequest::Method, const Inspector::ArgList&) +{ + std::vector threads = ProcessInfo::threads(); + string result = " TID NAME S User Time System Time\n"; + result.reserve(threads.size() * 64); + string stat; + for (pid_t tid : threads) + { + char buf[256]; + snprintf(buf, sizeof buf, "/proc/%d/task/%d/stat", ProcessInfo::pid(), tid); + if (FileUtil::readFile(buf, 65536, &stat) == 0) + { + StringPiece name = ProcessInfo::procname(stat); + const char* rp = name.end(); + assert(*rp == ')'); + const char* state = rp + 2; + *const_cast(rp) = '\0'; // don't do this at home + StringPiece data(stat); + data.remove_prefix(static_cast(state - data.data() + 2)); + ProcessInfo::CpuTime t = getCpuTime(data); + snprintf(buf, sizeof buf, "%5d %-16s %c %12.3f %12.3f\n", + tid, name.data(), *state, t.userSeconds, t.systemSeconds); + result += buf; + } + } + return result; +} + diff --git a/include/muduo/net/inspect/ProcessInspector.h b/include/muduo/net/inspect/ProcessInspector.h new file mode 100644 index 0000000..f1df478 --- /dev/null +++ b/include/muduo/net/inspect/ProcessInspector.h @@ -0,0 +1,38 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_PROCESSINSPECTOR_H +#define MUDUO_NET_INSPECT_PROCESSINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class ProcessInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string overview(HttpRequest::Method, const Inspector::ArgList&); + static string pid(HttpRequest::Method, const Inspector::ArgList&); + static string procStatus(HttpRequest::Method, const Inspector::ArgList&); + static string openedFiles(HttpRequest::Method, const Inspector::ArgList&); + static string threads(HttpRequest::Method, const Inspector::ArgList&); + + static string username_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_PROCESSINSPECTOR_H diff --git a/include/muduo/net/inspect/SystemInspector.cc b/include/muduo/net/inspect/SystemInspector.cc new file mode 100644 index 0000000..fb45e76 --- /dev/null +++ b/include/muduo/net/inspect/SystemInspector.cc @@ -0,0 +1,132 @@ +// Copyright 2014, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/SystemInspector.h" +#include "muduo/base/FileUtil.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace inspect +{ +string uptime(Timestamp now, Timestamp start, bool showMicroseconds); +long getLong(const string& content, const char* key); +int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); +} +} + +using namespace muduo::inspect; + +void SystemInspector::registerCommands(Inspector* ins) +{ + ins->add("sys", "overview", SystemInspector::overview, "print system overview"); + ins->add("sys", "loadavg", SystemInspector::loadavg, "print /proc/loadavg"); + ins->add("sys", "version", SystemInspector::version, "print /proc/version"); + ins->add("sys", "cpuinfo", SystemInspector::cpuinfo, "print /proc/cpuinfo"); + ins->add("sys", "meminfo", SystemInspector::meminfo, "print /proc/meminfo"); + ins->add("sys", "stat", SystemInspector::stat, "print /proc/stat"); +} + +string SystemInspector::loadavg(HttpRequest::Method, const Inspector::ArgList&) +{ + string loadavg; + FileUtil::readFile("/proc/loadavg", 65536, &loadavg); + return loadavg; +} + +string SystemInspector::version(HttpRequest::Method, const Inspector::ArgList&) +{ + string version; + FileUtil::readFile("/proc/version", 65536, &version); + return version; +} + +string SystemInspector::cpuinfo(HttpRequest::Method, const Inspector::ArgList&) +{ + string cpuinfo; + FileUtil::readFile("/proc/cpuinfo", 65536, &cpuinfo); + return cpuinfo; +} + +string SystemInspector::meminfo(HttpRequest::Method, const Inspector::ArgList&) +{ + string meminfo; + FileUtil::readFile("/proc/meminfo", 65536, &meminfo); + return meminfo; +} + +string SystemInspector::stat(HttpRequest::Method, const Inspector::ArgList&) +{ + string stat; + FileUtil::readFile("/proc/stat", 65536, &stat); + return stat; +} + +string SystemInspector::overview(HttpRequest::Method, const Inspector::ArgList&) +{ + string result; + result.reserve(1024); + Timestamp now = Timestamp::now(); + result += "Page generated at "; + result += now.toFormattedString(); + result += " (UTC)\n"; + // Hardware and OS + { + struct utsname un; + if (::uname(&un) == 0) + { + stringPrintf(&result, "Hostname: %s\n", un.nodename); + stringPrintf(&result, "Machine: %s\n", un.machine); + stringPrintf(&result, "OS: %s %s %s\n", un.sysname, un.release, un.version); + } + } + string stat; + FileUtil::readFile("/proc/stat", 65536, &stat); + Timestamp bootTime(Timestamp::kMicroSecondsPerSecond * getLong(stat, "btime ")); + result += "Boot time: "; + result += bootTime.toFormattedString(false /* show microseconds */); + result += " (UTC)\n"; + result += "Up time: "; + result += uptime(now, bootTime, false /* show microseconds */); + result += "\n"; + + // CPU load + { + string loadavg; + FileUtil::readFile("/proc/loadavg", 65536, &loadavg); + stringPrintf(&result, "Processes created: %ld\n", getLong(stat, "processes ")); + stringPrintf(&result, "Loadavg: %s\n", loadavg.c_str()); + } + + // Memory + { + string meminfo; + FileUtil::readFile("/proc/meminfo", 65536, &meminfo); + long total_kb = getLong(meminfo, "MemTotal:"); + long free_kb = getLong(meminfo, "MemFree:"); + long buffers_kb = getLong(meminfo, "Buffers:"); + long cached_kb = getLong(meminfo, "Cached:"); + + stringPrintf(&result, "Total Memory: %6ld MiB\n", total_kb / 1024); + stringPrintf(&result, "Free Memory: %6ld MiB\n", free_kb / 1024); + stringPrintf(&result, "Buffers: %6ld MiB\n", buffers_kb / 1024); + stringPrintf(&result, "Cached: %6ld MiB\n", cached_kb / 1024); + stringPrintf(&result, "Real Used: %6ld MiB\n", (total_kb - free_kb - buffers_kb - cached_kb) / 1024); + stringPrintf(&result, "Real Free: %6ld MiB\n", (free_kb + buffers_kb + cached_kb) / 1024); + + // Swap + } + // Disk + // Network + return result; +} diff --git a/include/muduo/net/inspect/SystemInspector.h b/include/muduo/net/inspect/SystemInspector.h new file mode 100644 index 0000000..8f2a604 --- /dev/null +++ b/include/muduo/net/inspect/SystemInspector.h @@ -0,0 +1,37 @@ +// Copyright 2014, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H +#define MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class SystemInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string overview(HttpRequest::Method, const Inspector::ArgList&); + static string loadavg(HttpRequest::Method, const Inspector::ArgList&); + static string version(HttpRequest::Method, const Inspector::ArgList&); + static string cpuinfo(HttpRequest::Method, const Inspector::ArgList&); + static string meminfo(HttpRequest::Method, const Inspector::ArgList&); + static string stat(HttpRequest::Method, const Inspector::ArgList&); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H diff --git a/include/muduo/net/inspect/tests/BUILD.bazel b/include/muduo/net/inspect/tests/BUILD.bazel new file mode 100644 index 0000000..e7f0ca7 --- /dev/null +++ b/include/muduo/net/inspect/tests/BUILD.bazel @@ -0,0 +1,7 @@ +cc_binary( + name = "inspector", + srcs = ["Inspector_test.cc"], + deps = [ + "//muduo/net/inspect", + ], +) diff --git a/include/muduo/net/inspect/tests/Inspector_test.cc b/include/muduo/net/inspect/tests/Inspector_test.cc new file mode 100644 index 0000000..20025ff --- /dev/null +++ b/include/muduo/net/inspect/tests/Inspector_test.cc @@ -0,0 +1,15 @@ +#include "muduo/net/inspect/Inspector.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + EventLoop loop; + EventLoopThread t; + Inspector ins(t.startLoop(), InetAddress(12345), "test"); + loop.loop(); +} + diff --git a/include/muduo/net/poller/DefaultPoller.cc b/include/muduo/net/poller/DefaultPoller.cc new file mode 100644 index 0000000..5ea0d03 --- /dev/null +++ b/include/muduo/net/poller/DefaultPoller.cc @@ -0,0 +1,27 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Poller.h" +#include "muduo/net/poller/PollPoller.h" +#include "muduo/net/poller/EPollPoller.h" + +#include + +using namespace muduo::net; + +Poller* Poller::newDefaultPoller(EventLoop* loop) +{ + if (::getenv("MUDUO_USE_POLL")) + { + return new PollPoller(loop); + } + else + { + return new EPollPoller(loop); + } +} diff --git a/include/muduo/net/poller/EPollPoller.cc b/include/muduo/net/poller/EPollPoller.cc new file mode 100644 index 0000000..b2f913a --- /dev/null +++ b/include/muduo/net/poller/EPollPoller.cc @@ -0,0 +1,208 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/poller/EPollPoller.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" + +#include +#include +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +// On Linux, the constants of poll(2) and epoll(4) +// are expected to be the same. +static_assert(EPOLLIN == POLLIN, "epoll uses same flag values as poll"); +static_assert(EPOLLPRI == POLLPRI, "epoll uses same flag values as poll"); +static_assert(EPOLLOUT == POLLOUT, "epoll uses same flag values as poll"); +static_assert(EPOLLRDHUP == POLLRDHUP, "epoll uses same flag values as poll"); +static_assert(EPOLLERR == POLLERR, "epoll uses same flag values as poll"); +static_assert(EPOLLHUP == POLLHUP, "epoll uses same flag values as poll"); + +namespace +{ +const int kNew = -1; +const int kAdded = 1; +const int kDeleted = 2; +} + +EPollPoller::EPollPoller(EventLoop* loop) + : Poller(loop), + epollfd_(::epoll_create1(EPOLL_CLOEXEC)), + events_(kInitEventListSize) +{ + if (epollfd_ < 0) + { + LOG_SYSFATAL << "EPollPoller::EPollPoller"; + } +} + +EPollPoller::~EPollPoller() +{ + ::close(epollfd_); +} + +Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) +{ + LOG_TRACE << "fd total count " << channels_.size(); + int numEvents = ::epoll_wait(epollfd_, + &*events_.begin(), + static_cast(events_.size()), + timeoutMs); + int savedErrno = errno; + Timestamp now(Timestamp::now()); + if (numEvents > 0) + { + LOG_TRACE << numEvents << " events happened"; + fillActiveChannels(numEvents, activeChannels); + if (implicit_cast(numEvents) == events_.size()) + { + events_.resize(events_.size()*2); + } + } + else if (numEvents == 0) + { + LOG_TRACE << "nothing happened"; + } + else + { + // error happens, log uncommon ones + if (savedErrno != EINTR) + { + errno = savedErrno; + LOG_SYSERR << "EPollPoller::poll()"; + } + } + return now; +} + +void EPollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const +{ + assert(implicit_cast(numEvents) <= events_.size()); + for (int i = 0; i < numEvents; ++i) + { + Channel* channel = static_cast(events_[i].data.ptr); +#ifndef NDEBUG + int fd = channel->fd(); + ChannelMap::const_iterator it = channels_.find(fd); + assert(it != channels_.end()); + assert(it->second == channel); +#endif + channel->set_revents(events_[i].events); + activeChannels->push_back(channel); + } +} + +void EPollPoller::updateChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + const int index = channel->index(); + LOG_TRACE << "fd = " << channel->fd() + << " events = " << channel->events() << " index = " << index; + if (index == kNew || index == kDeleted) + { + // a new one, add with EPOLL_CTL_ADD + int fd = channel->fd(); + if (index == kNew) + { + assert(channels_.find(fd) == channels_.end()); + channels_[fd] = channel; + } + else // index == kDeleted + { + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + } + + channel->set_index(kAdded); + update(EPOLL_CTL_ADD, channel); + } + else + { + // update existing one with EPOLL_CTL_MOD/DEL + int fd = channel->fd(); + (void)fd; + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(index == kAdded); + if (channel->isNoneEvent()) + { + update(EPOLL_CTL_DEL, channel); + channel->set_index(kDeleted); + } + else + { + update(EPOLL_CTL_MOD, channel); + } + } +} + +void EPollPoller::removeChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + int fd = channel->fd(); + LOG_TRACE << "fd = " << fd; + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(channel->isNoneEvent()); + int index = channel->index(); + assert(index == kAdded || index == kDeleted); + size_t n = channels_.erase(fd); + (void)n; + assert(n == 1); + + if (index == kAdded) + { + update(EPOLL_CTL_DEL, channel); + } + channel->set_index(kNew); +} + +void EPollPoller::update(int operation, Channel* channel) +{ + struct epoll_event event; + memZero(&event, sizeof event); + event.events = channel->events(); + event.data.ptr = channel; + int fd = channel->fd(); + LOG_TRACE << "epoll_ctl op = " << operationToString(operation) + << " fd = " << fd << " event = { " << channel->eventsToString() << " }"; + if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) + { + if (operation == EPOLL_CTL_DEL) + { + LOG_SYSERR << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; + } + else + { + LOG_SYSFATAL << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; + } + } +} + +const char* EPollPoller::operationToString(int op) +{ + switch (op) + { + case EPOLL_CTL_ADD: + return "ADD"; + case EPOLL_CTL_DEL: + return "DEL"; + case EPOLL_CTL_MOD: + return "MOD"; + default: + assert(false && "ERROR op"); + return "Unknown Operation"; + } +} diff --git a/include/muduo/net/poller/EPollPoller.h b/include/muduo/net/poller/EPollPoller.h new file mode 100644 index 0000000..c112f18 --- /dev/null +++ b/include/muduo/net/poller/EPollPoller.h @@ -0,0 +1,55 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H +#define MUDUO_NET_POLLER_EPOLLPOLLER_H + +#include "muduo/net/Poller.h" + +#include + +struct epoll_event; + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with epoll(4). +/// +class EPollPoller : public Poller +{ + public: + EPollPoller(EventLoop* loop); + ~EPollPoller() override; + + Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; + void updateChannel(Channel* channel) override; + void removeChannel(Channel* channel) override; + + private: + static const int kInitEventListSize = 16; + + static const char* operationToString(int op); + + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; + void update(int operation, Channel* channel); + + typedef std::vector EventList; + + int epollfd_; + EventList events_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_POLLER_EPOLLPOLLER_H diff --git a/include/muduo/net/poller/PollPoller.cc b/include/muduo/net/poller/PollPoller.cc new file mode 100644 index 0000000..7933079 --- /dev/null +++ b/include/muduo/net/poller/PollPoller.cc @@ -0,0 +1,141 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/poller/PollPoller.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Types.h" +#include "muduo/net/Channel.h" + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +PollPoller::PollPoller(EventLoop* loop) + : Poller(loop) +{ +} + +PollPoller::~PollPoller() = default; + +Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) +{ + // XXX pollfds_ shouldn't change + int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); + int savedErrno = errno; + Timestamp now(Timestamp::now()); + if (numEvents > 0) + { + LOG_TRACE << numEvents << " events happened"; + fillActiveChannels(numEvents, activeChannels); + } + else if (numEvents == 0) + { + LOG_TRACE << " nothing happened"; + } + else + { + if (savedErrno != EINTR) + { + errno = savedErrno; + LOG_SYSERR << "PollPoller::poll()"; + } + } + return now; +} + +void PollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const +{ + for (PollFdList::const_iterator pfd = pollfds_.begin(); + pfd != pollfds_.end() && numEvents > 0; ++pfd) + { + if (pfd->revents > 0) + { + --numEvents; + ChannelMap::const_iterator ch = channels_.find(pfd->fd); + assert(ch != channels_.end()); + Channel* channel = ch->second; + assert(channel->fd() == pfd->fd); + channel->set_revents(pfd->revents); + // pfd->revents = 0; + activeChannels->push_back(channel); + } + } +} + +void PollPoller::updateChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); + if (channel->index() < 0) + { + // a new one, add to pollfds_ + assert(channels_.find(channel->fd()) == channels_.end()); + struct pollfd pfd; + pfd.fd = channel->fd(); + pfd.events = static_cast(channel->events()); + pfd.revents = 0; + pollfds_.push_back(pfd); + int idx = static_cast(pollfds_.size())-1; + channel->set_index(idx); + channels_[pfd.fd] = channel; + } + else + { + // update existing one + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + struct pollfd& pfd = pollfds_[idx]; + assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); + pfd.fd = channel->fd(); + pfd.events = static_cast(channel->events()); + pfd.revents = 0; + if (channel->isNoneEvent()) + { + // ignore this pollfd + pfd.fd = -channel->fd()-1; + } + } +} + +void PollPoller::removeChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd(); + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + assert(channel->isNoneEvent()); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + const struct pollfd& pfd = pollfds_[idx]; (void)pfd; + assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); + size_t n = channels_.erase(channel->fd()); + assert(n == 1); (void)n; + if (implicit_cast(idx) == pollfds_.size()-1) + { + pollfds_.pop_back(); + } + else + { + int channelAtEnd = pollfds_.back().fd; + iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); + if (channelAtEnd < 0) + { + channelAtEnd = -channelAtEnd-1; + } + channels_[channelAtEnd]->set_index(idx); + pollfds_.pop_back(); + } +} + diff --git a/include/muduo/net/poller/PollPoller.h b/include/muduo/net/poller/PollPoller.h new file mode 100644 index 0000000..4657534 --- /dev/null +++ b/include/muduo/net/poller/PollPoller.h @@ -0,0 +1,49 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_POLLPOLLER_H +#define MUDUO_NET_POLLER_POLLPOLLER_H + +#include "muduo/net/Poller.h" + +#include + +struct pollfd; + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with poll(2). +/// +class PollPoller : public Poller +{ + public: + + PollPoller(EventLoop* loop); + ~PollPoller() override; + + Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; + void updateChannel(Channel* channel) override; + void removeChannel(Channel* channel) override; + + private: + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; + + typedef std::vector PollFdList; + PollFdList pollfds_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_POLLER_POLLPOLLER_H diff --git a/include/muduo/net/protobuf/BufferStream.h b/include/muduo/net/protobuf/BufferStream.h new file mode 100644 index 0000000..322bc44 --- /dev/null +++ b/include/muduo/net/protobuf/BufferStream.h @@ -0,0 +1,56 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. +#pragma once +#include "muduo/net/Buffer.h" +#include +namespace muduo +{ +namespace net +{ + +// FIXME: +// class BufferInputStream : google::protobuf::io::ZeroCopyInputStream +// { +// }; + +class BufferOutputStream : public google::protobuf::io::ZeroCopyOutputStream +{ + public: + BufferOutputStream(Buffer* buf) + : buffer_(CHECK_NOTNULL(buf)), + originalSize_(buffer_->readableBytes()) + { + } + + virtual bool Next(void** data, int* size) // override + { + buffer_->ensureWritableBytes(4096); + *data = buffer_->beginWrite(); + *size = static_cast(buffer_->writableBytes()); + buffer_->hasWritten(*size); + return true; + } + + virtual void BackUp(int count) // override + { + buffer_->unwrite(count); + } + + virtual int64_t ByteCount() const // override + { + return buffer_->readableBytes() - originalSize_; + } + + private: + Buffer* buffer_; + size_t originalSize_; +}; + +} +} diff --git a/include/muduo/net/protobuf/CMakeLists.txt b/include/muduo/net/protobuf/CMakeLists.txt new file mode 100644 index 0000000..a7e49d9 --- /dev/null +++ b/include/muduo/net/protobuf/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(muduo_protobuf_codec ProtobufCodecLite.cc) +set_target_properties(muduo_protobuf_codec PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +target_link_libraries(muduo_protobuf_codec muduo_net protobuf z) + +#add_library(muduo_protobuf_codec_cpp11 ProtobufCodecLite.cc) +#set_target_properties(muduo_protobuf_codec_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") +#target_link_libraries(muduo_protobuf_codec_cpp11 muduo_net_cpp11 protobuf z) + + +install(TARGETS muduo_protobuf_codec DESTINATION lib) +#install(TARGETS muduo_protobuf_codec_cpp11 DESTINATION lib) + +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION include/muduo/net/protobuf) + diff --git a/include/muduo/net/protobuf/ProtobufCodecLite.cc b/include/muduo/net/protobuf/ProtobufCodecLite.cc new file mode 100644 index 0000000..9d406ee --- /dev/null +++ b/include/muduo/net/protobuf/ProtobufCodecLite.cc @@ -0,0 +1,243 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protobuf/ProtobufCodecLite.h" +// #include + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/TcpConnection.h" +#include "muduo/net/protorpc/google-inl.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + int ProtobufVersionCheck() + { + GOOGLE_PROTOBUF_VERIFY_VERSION; + return 0; + } + int __attribute__ ((unused)) dummy = ProtobufVersionCheck(); +} + +void ProtobufCodecLite::send(const TcpConnectionPtr& conn, + const ::google::protobuf::Message& message) +{ + // FIXME: serialize to TcpConnection::outputBuffer() + muduo::net::Buffer buf; + fillEmptyBuffer(&buf, message); + conn->send(&buf); +} + +void ProtobufCodecLite::fillEmptyBuffer(muduo::net::Buffer* buf, + const google::protobuf::Message& message) +{ + assert(buf->readableBytes() == 0); + // FIXME: can we move serialization & checksum to other thread? + buf->append(tag_); + + int byte_size = serializeToBuffer(message, buf); + + int32_t checkSum = checksum(buf->peek(), static_cast(buf->readableBytes())); + buf->appendInt32(checkSum); + assert(buf->readableBytes() == tag_.size() + byte_size + kChecksumLen); (void) byte_size; + int32_t len = sockets::hostToNetwork32(static_cast(buf->readableBytes())); + buf->prepend(&len, sizeof len); +} + +void ProtobufCodecLite::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + while (buf->readableBytes() >= static_cast(kMinMessageLen+kHeaderLen)) + { + const int32_t len = buf->peekInt32(); + if (len > kMaxMessageLen || len < kMinMessageLen) + { + errorCallback_(conn, buf, receiveTime, kInvalidLength); + break; + } + else if (buf->readableBytes() >= implicit_cast(kHeaderLen+len)) + { + if (rawCb_ && !rawCb_(conn, StringPiece(buf->peek(), kHeaderLen+len), receiveTime)) + { + buf->retrieve(kHeaderLen+len); + continue; + } + MessagePtr message(prototype_->New()); + // FIXME: can we move deserialization & callback to other thread? + ErrorCode errorCode = parse(buf->peek()+kHeaderLen, len, message.get()); + if (errorCode == kNoError) + { + // FIXME: try { } catch (...) { } + messageCallback_(conn, message, receiveTime); + buf->retrieve(kHeaderLen+len); + } + else + { + errorCallback_(conn, buf, receiveTime, errorCode); + break; + } + } + else + { + break; + } + } +} + +bool ProtobufCodecLite::parseFromBuffer(StringPiece buf, google::protobuf::Message* message) +{ + return message->ParseFromArray(buf.data(), buf.size()); +} + +int ProtobufCodecLite::serializeToBuffer(const google::protobuf::Message& message, Buffer* buf) +{ + // TODO: use BufferOutputStream + // BufferOutputStream os(buf); + // message.SerializeToZeroCopyStream(&os); + // return static_cast(os.ByteCount()); + + // code copied from MessageLite::SerializeToArray() and MessageLite::SerializePartialToArray(). + GOOGLE_DCHECK(message.IsInitialized()) << InitializationErrorMessage("serialize", message); + + /** + * 'ByteSize()' of message is deprecated in Protocol Buffers v3.4.0 firstly. But, till to v3.11.0, it just getting start to be marked by '__attribute__((deprecated()))'. + * So, here, v3.9.2 is selected as maximum version using 'ByteSize()' to avoid potential effect for previous muduo code/projects as far as possible. + * Note: All information above just INFER from + * 1) https://github.com/protocolbuffers/protobuf/releases/tag/v3.4.0 + * 2) MACRO in file 'include/google/protobuf/port_def.inc'. eg. '#define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))'. + * In addition, usage of 'ToIntSize()' comes from Impl of ByteSize() in new version's Protocol Buffers. + */ + + #if GOOGLE_PROTOBUF_VERSION > 3009002 + int byte_size = google::protobuf::internal::ToIntSize(message.ByteSizeLong()); + #else + int byte_size = message.ByteSize(); + #endif + buf->ensureWritableBytes(byte_size + kChecksumLen); + + uint8_t* start = reinterpret_cast(buf->beginWrite()); + uint8_t* end = message.SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) + { + #if GOOGLE_PROTOBUF_VERSION > 3009002 + ByteSizeConsistencyError(byte_size, google::protobuf::internal::ToIntSize(message.ByteSizeLong()), static_cast(end - start)); + #else + ByteSizeConsistencyError(byte_size, message.ByteSize(), static_cast(end - start)); + #endif + } + buf->hasWritten(byte_size); + return byte_size; +} + +namespace +{ + const string kNoErrorStr = "NoError"; + const string kInvalidLengthStr = "InvalidLength"; + const string kCheckSumErrorStr = "CheckSumError"; + const string kInvalidNameLenStr = "InvalidNameLen"; + const string kUnknownMessageTypeStr = "UnknownMessageType"; + const string kParseErrorStr = "ParseError"; + const string kUnknownErrorStr = "UnknownError"; +} + +const string& ProtobufCodecLite::errorCodeToString(ErrorCode errorCode) +{ + switch (errorCode) + { + case kNoError: + return kNoErrorStr; + case kInvalidLength: + return kInvalidLengthStr; + case kCheckSumError: + return kCheckSumErrorStr; + case kInvalidNameLen: + return kInvalidNameLenStr; + case kUnknownMessageType: + return kUnknownMessageTypeStr; + case kParseError: + return kParseErrorStr; + default: + return kUnknownErrorStr; + } +} + +void ProtobufCodecLite::defaultErrorCallback(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp, + ErrorCode errorCode) +{ + LOG_ERROR << "ProtobufCodecLite::defaultErrorCallback - " << errorCodeToString(errorCode); + if (conn && conn->connected()) + { + conn->shutdown(); + } +} + +int32_t ProtobufCodecLite::asInt32(const char* buf) +{ + int32_t be32 = 0; + ::memcpy(&be32, buf, sizeof(be32)); + return sockets::networkToHost32(be32); +} + +int32_t ProtobufCodecLite::checksum(const void* buf, int len) +{ + return static_cast( + ::adler32(1, static_cast(buf), len)); +} + +bool ProtobufCodecLite::validateChecksum(const char* buf, int len) +{ + // check sum + int32_t expectedCheckSum = asInt32(buf + len - kChecksumLen); + int32_t checkSum = checksum(buf, len - kChecksumLen); + return checkSum == expectedCheckSum; +} + +ProtobufCodecLite::ErrorCode ProtobufCodecLite::parse(const char* buf, + int len, + ::google::protobuf::Message* message) +{ + ErrorCode error = kNoError; + + if (validateChecksum(buf, len)) + { + if (memcmp(buf, tag_.data(), tag_.size()) == 0) + { + // parse from buffer + const char* data = buf + tag_.size(); + int32_t dataLen = len - kChecksumLen - static_cast(tag_.size()); + if (parseFromBuffer(StringPiece(data, dataLen), message)) + { + error = kNoError; + } + else + { + error = kParseError; + } + } + else + { + error = kUnknownMessageType; + } + } + else + { + error = kCheckSumError; + } + + return error; +} + diff --git a/include/muduo/net/protobuf/ProtobufCodecLite.h b/include/muduo/net/protobuf/ProtobufCodecLite.h new file mode 100644 index 0000000..134ee7b --- /dev/null +++ b/include/muduo/net/protobuf/ProtobufCodecLite.h @@ -0,0 +1,192 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +// For Protobuf codec supporting multiple message types, check +// examples/protobuf/codec + +#ifndef MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H +#define MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" + +#include +#include + +namespace google +{ +namespace protobuf +{ +class Message; +} +} + +namespace muduo +{ +namespace net +{ + +typedef std::shared_ptr MessagePtr; + +// wire format +// +// Field Length Content +// +// size 4-byte M+N+4 +// tag M-byte could be "RPC0", etc. +// payload N-byte +// checksum 4-byte adler32 of tag+payload +// +// This is an internal class, you should use ProtobufCodecT instead. +class ProtobufCodecLite : noncopyable +{ + public: + const static int kHeaderLen = sizeof(int32_t); + const static int kChecksumLen = sizeof(int32_t); + const static int kMaxMessageLen = 64*1024*1024; // same as codec_stream.h kDefaultTotalBytesLimit + + enum ErrorCode + { + kNoError = 0, + kInvalidLength, + kCheckSumError, + kInvalidNameLen, + kUnknownMessageType, + kParseError, + }; + + // return false to stop parsing protobuf message + typedef std::function RawMessageCallback; + + typedef std::function ProtobufMessageCallback; + + typedef std::function ErrorCallback; + + ProtobufCodecLite(const ::google::protobuf::Message* prototype, + StringPiece tagArg, + const ProtobufMessageCallback& messageCb, + const RawMessageCallback& rawCb = RawMessageCallback(), + const ErrorCallback& errorCb = defaultErrorCallback) + : prototype_(prototype), + tag_(tagArg.as_string()), + messageCallback_(messageCb), + rawCb_(rawCb), + errorCallback_(errorCb), + kMinMessageLen(tagArg.size() + kChecksumLen) + { + } + + virtual ~ProtobufCodecLite() = default; + + const string& tag() const { return tag_; } + + void send(const TcpConnectionPtr& conn, + const ::google::protobuf::Message& message); + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + + virtual bool parseFromBuffer(StringPiece buf, google::protobuf::Message* message); + virtual int serializeToBuffer(const google::protobuf::Message& message, Buffer* buf); + + static const string& errorCodeToString(ErrorCode errorCode); + + // public for unit tests + ErrorCode parse(const char* buf, int len, ::google::protobuf::Message* message); + void fillEmptyBuffer(muduo::net::Buffer* buf, const google::protobuf::Message& message); + + static int32_t checksum(const void* buf, int len); + static bool validateChecksum(const char* buf, int len); + static int32_t asInt32(const char* buf); + static void defaultErrorCallback(const TcpConnectionPtr&, + Buffer*, + Timestamp, + ErrorCode); + + private: + const ::google::protobuf::Message* prototype_; + const string tag_; + ProtobufMessageCallback messageCallback_; + RawMessageCallback rawCb_; + ErrorCallback errorCallback_; + const int kMinMessageLen; +}; + +template // TAG must be a variable with external linkage, not a string literal +class ProtobufCodecLiteT +{ + static_assert(std::is_base_of::value, "CODEC should be derived from ProtobufCodecLite"); + public: + typedef std::shared_ptr ConcreteMessagePtr; + typedef std::function ProtobufMessageCallback; + typedef ProtobufCodecLite::RawMessageCallback RawMessageCallback; + typedef ProtobufCodecLite::ErrorCallback ErrorCallback; + + explicit ProtobufCodecLiteT(const ProtobufMessageCallback& messageCb, + const RawMessageCallback& rawCb = RawMessageCallback(), + const ErrorCallback& errorCb = ProtobufCodecLite::defaultErrorCallback) + : messageCallback_(messageCb), + codec_(&MSG::default_instance(), + TAG, + std::bind(&ProtobufCodecLiteT::onRpcMessage, this, _1, _2, _3), + rawCb, + errorCb) + { + } + + const string& tag() const { return codec_.tag(); } + + void send(const TcpConnectionPtr& conn, + const MSG& message) + { + codec_.send(conn, message); + } + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) + { + codec_.onMessage(conn, buf, receiveTime); + } + + // internal + void onRpcMessage(const TcpConnectionPtr& conn, + const MessagePtr& message, + Timestamp receiveTime) + { + messageCallback_(conn, ::muduo::down_pointer_cast(message), receiveTime); + } + + void fillEmptyBuffer(muduo::net::Buffer* buf, const MSG& message) + { + codec_.fillEmptyBuffer(buf, message); + } + + private: + ProtobufMessageCallback messageCallback_; + CODEC codec_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H diff --git a/include/muduo/net/protorpc/CMakeLists.txt b/include/muduo/net/protorpc/CMakeLists.txt new file mode 100644 index 0000000..1e5f153 --- /dev/null +++ b/include/muduo/net/protorpc/CMakeLists.txt @@ -0,0 +1,42 @@ +add_custom_command(OUTPUT rpc.pb.cc rpc.pb.h + COMMAND protoc + ARGS --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/rpc.proto -I${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS rpc.proto + VERBATIM ) + +set_source_files_properties(rpc.pb.cc PROPERTIES COMPILE_FLAGS "-Wno-conversion") +include_directories(${PROJECT_BINARY_DIR}) + +add_library(muduo_protorpc_wire rpc.pb.cc RpcCodec.cc) +set_target_properties(muduo_protorpc_wire PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") + +#add_library(muduo_protorpc_wire_cpp11 rpc.pb.cc RpcCodec.cc) +#set_target_properties(muduo_protorpc_wire_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") + +if(MUDUO_BUILD_EXAMPLES) +add_executable(protobuf_rpc_wire_test RpcCodec_test.cc) +target_link_libraries(protobuf_rpc_wire_test muduo_protorpc_wire muduo_protobuf_codec) +set_target_properties(protobuf_rpc_wire_test PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +endif() + +add_library(muduo_protorpc RpcChannel.cc RpcServer.cc) +set_target_properties(muduo_protorpc PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +target_link_libraries(muduo_protorpc muduo_protorpc_wire muduo_protobuf_codec muduo_net protobuf z) + +if(TCMALLOC_LIBRARY) + target_link_libraries(muduo_protorpc tcmalloc_and_profiler) +endif() + +install(TARGETS muduo_protorpc_wire muduo_protorpc DESTINATION lib) +#install(TARGETS muduo_protorpc_wire_cpp11 DESTINATION lib) + +set(HEADERS + RpcCodec.h + RpcChannel.h + RpcServer.h + rpc.proto + rpcservice.proto + ${PROJECT_BINARY_DIR}/muduo/net/protorpc/rpc.pb.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/protorpc) + diff --git a/include/muduo/net/protorpc/README b/include/muduo/net/protorpc/README new file mode 100644 index 0000000..0db4c85 --- /dev/null +++ b/include/muduo/net/protorpc/README @@ -0,0 +1,5 @@ +This is an proof of concept implementation of Google Protobuf RPC using muduo. +The object lifetime management is for from ideal and doesn't follow the usual +muduo approach. + +Please consider using http://github.com/chenshuo/muduo-protorpc instead. diff --git a/include/muduo/net/protorpc/RpcChannel.cc b/include/muduo/net/protorpc/RpcChannel.cc new file mode 100644 index 0000000..d18e081 --- /dev/null +++ b/include/muduo/net/protorpc/RpcChannel.cc @@ -0,0 +1,184 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcChannel.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/protorpc/rpc.pb.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +RpcChannel::RpcChannel() + : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), + services_(NULL) +{ + LOG_INFO << "RpcChannel::ctor - " << this; +} + +RpcChannel::RpcChannel(const TcpConnectionPtr& conn) + : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), + conn_(conn), + services_(NULL) +{ + LOG_INFO << "RpcChannel::ctor - " << this; +} + +RpcChannel::~RpcChannel() +{ + LOG_INFO << "RpcChannel::dtor - " << this; + for (const auto& outstanding : outstandings_) + { + OutstandingCall out = outstanding.second; + delete out.response; + delete out.done; + } +} + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). +void RpcChannel::CallMethod(const ::google::protobuf::MethodDescriptor* method, + google::protobuf::RpcController* controller, + const ::google::protobuf::Message* request, + ::google::protobuf::Message* response, + ::google::protobuf::Closure* done) +{ + RpcMessage message; + message.set_type(REQUEST); + int64_t id = id_.incrementAndGet(); + message.set_id(id); + message.set_service(method->service()->full_name()); + message.set_method(method->name()); + message.set_request(request->SerializeAsString()); // FIXME: error check + + OutstandingCall out = { response, done }; + { + MutexLockGuard lock(mutex_); + outstandings_[id] = out; + } + codec_.send(conn_, message); +} + +void RpcChannel::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + codec_.onMessage(conn, buf, receiveTime); +} + +void RpcChannel::onRpcMessage(const TcpConnectionPtr& conn, + const RpcMessagePtr& messagePtr, + Timestamp receiveTime) +{ + assert(conn == conn_); + //printf("%s\n", message.DebugString().c_str()); + RpcMessage& message = *messagePtr; + if (message.type() == RESPONSE) + { + int64_t id = message.id(); + assert(message.has_response() || message.has_error()); + + OutstandingCall out = { NULL, NULL }; + + { + MutexLockGuard lock(mutex_); + std::map::iterator it = outstandings_.find(id); + if (it != outstandings_.end()) + { + out = it->second; + outstandings_.erase(it); + } + } + + if (out.response) + { + std::unique_ptr d(out.response); + if (message.has_response()) + { + out.response->ParseFromString(message.response()); + } + if (out.done) + { + out.done->Run(); + } + } + } + else if (message.type() == REQUEST) + { + // FIXME: extract to a function + ErrorCode error = WRONG_PROTO; + if (services_) + { + std::map::const_iterator it = services_->find(message.service()); + if (it != services_->end()) + { + google::protobuf::Service* service = it->second; + assert(service != NULL); + const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); + const google::protobuf::MethodDescriptor* method + = desc->FindMethodByName(message.method()); + if (method) + { + std::unique_ptr request(service->GetRequestPrototype(method).New()); + if (request->ParseFromString(message.request())) + { + google::protobuf::Message* response = service->GetResponsePrototype(method).New(); + // response is deleted in doneCallback + int64_t id = message.id(); + service->CallMethod(method, NULL, get_pointer(request), response, + NewCallback(this, &RpcChannel::doneCallback, response, id)); + error = NO_ERROR; + } + else + { + error = INVALID_REQUEST; + } + } + else + { + error = NO_METHOD; + } + } + else + { + error = NO_SERVICE; + } + } + else + { + error = NO_SERVICE; + } + if (error != NO_ERROR) + { + RpcMessage response; + response.set_type(RESPONSE); + response.set_id(message.id()); + response.set_error(error); + codec_.send(conn_, response); + } + } + else if (message.type() == ERROR) + { + } +} + +void RpcChannel::doneCallback(::google::protobuf::Message* response, int64_t id) +{ + std::unique_ptr d(response); + RpcMessage message; + message.set_type(RESPONSE); + message.set_id(id); + message.set_response(response->SerializeAsString()); // FIXME: error check + codec_.send(conn_, message); +} + diff --git a/include/muduo/net/protorpc/RpcChannel.h b/include/muduo/net/protorpc/RpcChannel.h new file mode 100644 index 0000000..172b41e --- /dev/null +++ b/include/muduo/net/protorpc/RpcChannel.h @@ -0,0 +1,152 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCCHANNEL_H +#define MUDUO_NET_PROTORPC_RPCCHANNEL_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Mutex.h" +#include "muduo/net/protorpc/RpcCodec.h" + +#include + +#include + +// Service and RpcChannel classes are incorporated from +// google/protobuf/service.h + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +namespace google { +namespace protobuf { + +// Defined in other files. +class Descriptor; // descriptor.h +class ServiceDescriptor; // descriptor.h +class MethodDescriptor; // descriptor.h +class Message; // message.h + +class Closure; + +class RpcController; +class Service; + +} // namespace protobuf +} // namespace google + + +namespace muduo +{ +namespace net +{ + +// Abstract interface for an RPC channel. An RpcChannel represents a +// communication line to a Service which can be used to call that Service's +// methods. The Service may be running on another machine. Normally, you +// should not call an RpcChannel directly, but instead construct a stub Service +// wrapping it. Example: +// FIXME: update here +// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234"); +// MyService* service = new MyService::Stub(channel); +// service->MyMethod(request, &response, callback); +class RpcChannel : public ::google::protobuf::RpcChannel +{ + public: + RpcChannel(); + + explicit RpcChannel(const TcpConnectionPtr& conn); + + ~RpcChannel() override; + + void setConnection(const TcpConnectionPtr& conn) + { + conn_ = conn; + } + + void setServices(const std::map* services) + { + services_ = services; + } + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). + void CallMethod(const ::google::protobuf::MethodDescriptor* method, + ::google::protobuf::RpcController* controller, + const ::google::protobuf::Message* request, + ::google::protobuf::Message* response, + ::google::protobuf::Closure* done) override; + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + + private: + void onRpcMessage(const TcpConnectionPtr& conn, + const RpcMessagePtr& messagePtr, + Timestamp receiveTime); + + void doneCallback(::google::protobuf::Message* response, int64_t id); + + struct OutstandingCall + { + ::google::protobuf::Message* response; + ::google::protobuf::Closure* done; + }; + + RpcCodec codec_; + TcpConnectionPtr conn_; + AtomicInt64 id_; + + MutexLock mutex_; + std::map outstandings_ GUARDED_BY(mutex_); + + const std::map* services_; +}; +typedef std::shared_ptr RpcChannelPtr; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCCHANNEL_H diff --git a/include/muduo/net/protorpc/RpcCodec.cc b/include/muduo/net/protorpc/RpcCodec.cc new file mode 100644 index 0000000..e466e1d --- /dev/null +++ b/include/muduo/net/protorpc/RpcCodec.cc @@ -0,0 +1,37 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcCodec.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/TcpConnection.h" + +#include "muduo/net/protorpc/rpc.pb.h" +#include "muduo/net/protorpc/google-inl.h" + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + int ProtobufVersionCheck() + { + GOOGLE_PROTOBUF_VERIFY_VERSION; + return 0; + } + int dummy __attribute__ ((unused)) = ProtobufVersionCheck(); +} + +namespace muduo +{ +namespace net +{ +const char rpctag [] = "RPC0"; +} +} diff --git a/include/muduo/net/protorpc/RpcCodec.h b/include/muduo/net/protorpc/RpcCodec.h new file mode 100644 index 0000000..07fab9c --- /dev/null +++ b/include/muduo/net/protorpc/RpcCodec.h @@ -0,0 +1,45 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCCODEC_H +#define MUDUO_NET_PROTORPC_RPCCODEC_H + +#include "muduo/base/Timestamp.h" +#include "muduo/net/protobuf/ProtobufCodecLite.h" + +namespace muduo +{ +namespace net +{ + +class Buffer; +class TcpConnection; +typedef std::shared_ptr TcpConnectionPtr; + +class RpcMessage; +typedef std::shared_ptr RpcMessagePtr; +extern const char rpctag[];// = "RPC0"; + +// wire format +// +// Field Length Content +// +// size 4-byte N+8 +// "RPC0" 4-byte +// payload N-byte +// checksum 4-byte adler32 of "RPC0"+payload +// + +typedef ProtobufCodecLiteT RpcCodec; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCCODEC_H diff --git a/include/muduo/net/protorpc/RpcCodec_test.cc b/include/muduo/net/protorpc/RpcCodec_test.cc new file mode 100644 index 0000000..645fffd --- /dev/null +++ b/include/muduo/net/protorpc/RpcCodec_test.cc @@ -0,0 +1,81 @@ +#undef NDEBUG +#include "muduo/net/protorpc/RpcCodec.h" +#include "muduo/net/protorpc/rpc.pb.h" +#include "muduo/net/protobuf/ProtobufCodecLite.h" +#include "muduo/net/Buffer.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void rpcMessageCallback(const TcpConnectionPtr&, + const RpcMessagePtr&, + Timestamp) +{ +} + +MessagePtr g_msgptr; +void messageCallback(const TcpConnectionPtr&, + const MessagePtr& msg, + Timestamp) +{ + g_msgptr = msg; +} + +void print(const Buffer& buf) +{ + printf("encoded to %zd bytes\n", buf.readableBytes()); + for (size_t i = 0; i < buf.readableBytes(); ++i) + { + unsigned char ch = static_cast(buf.peek()[i]); + + printf("%2zd: 0x%02x %c\n", i, ch, isgraph(ch) ? ch : ' '); + } +} + +char rpctag[] = "RPC0"; + +int main() +{ + RpcMessage message; + message.set_type(REQUEST); + message.set_id(2); + char wire[] = "\0\0\0\x13" "RPC0" "\x08\x01\x11\x02\0\0\0\0\0\0\0" "\x0f\xef\x01\x32"; + string expected(wire, sizeof(wire)-1); + string s1, s2; + Buffer buf1, buf2; + { + RpcCodec codec(rpcMessageCallback); + codec.fillEmptyBuffer(&buf1, message); + print(buf1); + s1 = buf1.toStringPiece().as_string(); + } + + { + ProtobufCodecLite codec(&RpcMessage::default_instance(), "RPC0", messageCallback); + codec.fillEmptyBuffer(&buf2, message); + print(buf2); + s2 = buf2.toStringPiece().as_string(); + codec.onMessage(TcpConnectionPtr(), &buf1, Timestamp::now()); + assert(g_msgptr); + assert(g_msgptr->DebugString() == message.DebugString()); + g_msgptr.reset(); + } + assert(s1 == s2); + assert(s1 == expected); + assert(s2 == expected); + + { + Buffer buf; + ProtobufCodecLite codec(&RpcMessage::default_instance(), "XYZ", messageCallback); + codec.fillEmptyBuffer(&buf, message); + print(buf); + s2 = buf.toStringPiece().as_string(); + codec.onMessage(TcpConnectionPtr(), &buf, Timestamp::now()); + assert(g_msgptr); + assert(g_msgptr->DebugString() == message.DebugString()); + } + + google::protobuf::ShutdownProtobufLibrary(); +} diff --git a/include/muduo/net/protorpc/RpcServer.cc b/include/muduo/net/protorpc/RpcServer.cc new file mode 100644 index 0000000..fc1248b --- /dev/null +++ b/include/muduo/net/protorpc/RpcServer.cc @@ -0,0 +1,68 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/protorpc/RpcChannel.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +RpcServer::RpcServer(EventLoop* loop, + const InetAddress& listenAddr) + : server_(loop, listenAddr, "RpcServer") +{ + server_.setConnectionCallback( + std::bind(&RpcServer::onConnection, this, _1)); +// server_.setMessageCallback( +// std::bind(&RpcServer::onMessage, this, _1, _2, _3)); +} + +void RpcServer::registerService(google::protobuf::Service* service) +{ + const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); + services_[desc->full_name()] = service; +} + +void RpcServer::start() +{ + server_.start(); +} + +void RpcServer::onConnection(const TcpConnectionPtr& conn) +{ + LOG_INFO << "RpcServer - " << conn->peerAddress().toIpPort() << " -> " + << conn->localAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + if (conn->connected()) + { + RpcChannelPtr channel(new RpcChannel(conn)); + channel->setServices(&services_); + conn->setMessageCallback( + std::bind(&RpcChannel::onMessage, get_pointer(channel), _1, _2, _3)); + conn->setContext(channel); + } + else + { + conn->setContext(RpcChannelPtr()); + // FIXME: + } +} + +// void RpcServer::onMessage(const TcpConnectionPtr& conn, +// Buffer* buf, +// Timestamp time) +// { +// RpcChannelPtr& channel = boost::any_cast(conn->getContext()); +// channel->onMessage(conn, buf, time); +// } + diff --git a/include/muduo/net/protorpc/RpcServer.h b/include/muduo/net/protorpc/RpcServer.h new file mode 100644 index 0000000..6818801 --- /dev/null +++ b/include/muduo/net/protorpc/RpcServer.h @@ -0,0 +1,57 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCSERVER_H +#define MUDUO_NET_PROTORPC_RPCSERVER_H + +#include "muduo/net/TcpServer.h" + +namespace google { +namespace protobuf { + +class Service; + +} // namespace protobuf +} // namespace google + +namespace muduo +{ +namespace net +{ + +class RpcServer +{ + public: + RpcServer(EventLoop* loop, + const InetAddress& listenAddr); + + void setThreadNum(int numThreads) + { + server_.setThreadNum(numThreads); + } + + void registerService(::google::protobuf::Service*); + void start(); + + private: + void onConnection(const TcpConnectionPtr& conn); + + // void onMessage(const TcpConnectionPtr& conn, + // Buffer* buf, + // Timestamp time); + + TcpServer server_; + std::map services_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCSERVER_H diff --git a/include/muduo/net/protorpc/google-inl.h b/include/muduo/net/protorpc/google-inl.h new file mode 100644 index 0000000..2a905a9 --- /dev/null +++ b/include/muduo/net/protorpc/google-inl.h @@ -0,0 +1,84 @@ +// ByteSizeConsistencyError and InitializationErrorMessage are +// copied from google/protobuf/message_lite.cc + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Authors: wink@google.com (Wink Saville), +// kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +// When serializing, we first compute the byte size, then serialize the message. +// If serialization produces a different number of bytes than expected, we +// call this function, which crashes. The problem could be due to a bug in the +// protobuf implementation but is more likely caused by concurrent modification +// of the message. This function attempts to distinguish between the two and +// provide a useful error message. +inline +void ByteSizeConsistencyError(int byte_size_before_serialization, + int byte_size_after_serialization, + int bytes_produced_by_serialization) +{ + GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) + << "Protocol message was modified concurrently during serialization."; + GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) + << "Byte size calculation and serialization were inconsistent. This " + "may indicate a bug in protocol buffers or it may be caused by " + "concurrent modification of the message."; + GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; +} + +inline +std::string InitializationErrorMessage(const char* action, + const google::protobuf::MessageLite& message) +{ + // Note: We want to avoid depending on strutil in the lite library, otherwise + // we'd use: + // + // return strings::Substitute( + // "Can't $0 message of type \"$1\" because it is missing required " + // "fields: $2", + // action, message.GetTypeName(), + // message.InitializationErrorString()); + + std::string result; + result += "Can't "; + result += action; + result += " message of type \""; + result += message.GetTypeName(); + result += "\" because it is missing required fields: "; + result += message.InitializationErrorString(); + return result; +} + + diff --git a/include/muduo/net/protorpc/rpc.proto b/include/muduo/net/protorpc/rpc.proto new file mode 100644 index 0000000..941e235 --- /dev/null +++ b/include/muduo/net/protorpc/rpc.proto @@ -0,0 +1,36 @@ +package muduo.net; +// option go_package = "muduorpc"; +option java_package = "com.chenshuo.muduo.protorpc"; +option java_outer_classname = "RpcProto"; + +enum MessageType +{ + REQUEST = 1; + RESPONSE = 2; + ERROR = 3; // not used +} + +enum ErrorCode +{ + NO_ERROR = 0; + WRONG_PROTO = 1; + NO_SERVICE = 2; + NO_METHOD = 3; + INVALID_REQUEST = 4; + INVALID_RESPONSE = 5; + TIMEOUT = 6; +} + +message RpcMessage +{ + required MessageType type = 1; + required fixed64 id = 2; + + optional string service = 3; + optional string method = 4; + optional bytes request = 5; + + optional bytes response = 6; + + optional ErrorCode error = 7; +} diff --git a/include/muduo/net/protorpc/rpcservice.proto b/include/muduo/net/protorpc/rpcservice.proto new file mode 100644 index 0000000..f973234 --- /dev/null +++ b/include/muduo/net/protorpc/rpcservice.proto @@ -0,0 +1,44 @@ +package muduo.net; + +option cc_generic_services = true; +option java_generic_services = true; +option py_generic_services = true; + +option java_package = "com.chenshuo.muduo.protorpc"; +option java_outer_classname = "RpcServiceProto"; + +//import "google/protobuf/descriptor.proto"; +import "rpc.proto"; + +message ListRpcRequest +{ + optional string service_name = 1; + optional bool list_method = 2; +} + +message ListRpcResponse +{ + required ErrorCode error = 1; + repeated string service_name = 2; + repeated string method_name = 3; +} + +message GetServiceRequest +{ + required string service_name = 1; +} + +message GetServiceResponse +{ + required ErrorCode error = 1; + repeated string proto_file = 2; + repeated string proto_file_name = 3; +} + +// the meta service +service RpcService +{ + rpc listRpc (ListRpcRequest) returns (ListRpcResponse); + rpc getService (GetServiceRequest) returns (GetServiceResponse); +} + diff --git a/include/muduo/net/tests/Buffer_unittest.cc b/include/muduo/net/tests/Buffer_unittest.cc new file mode 100644 index 0000000..af7fb81 --- /dev/null +++ b/include/muduo/net/tests/Buffer_unittest.cc @@ -0,0 +1,170 @@ +#include "muduo/net/Buffer.h" + +//#define BOOST_TEST_MODULE BufferTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::net::Buffer; + +BOOST_AUTO_TEST_CASE(testBufferAppendRetrieve) +{ + Buffer buf; + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + const string str(200, 'x'); + buf.append(str); + BOOST_CHECK_EQUAL(buf.readableBytes(), str.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + const string str2 = buf.retrieveAsString(50); + BOOST_CHECK_EQUAL(str2.size(), 50); + BOOST_CHECK_EQUAL(buf.readableBytes(), str.size() - str2.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); + BOOST_CHECK_EQUAL(str2, string(50, 'x')); + + buf.append(str); + BOOST_CHECK_EQUAL(buf.readableBytes(), 2*str.size() - str2.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - 2*str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); + + const string str3 = buf.retrieveAllAsString(); + BOOST_CHECK_EQUAL(str3.size(), 350); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + BOOST_CHECK_EQUAL(str3, string(350, 'x')); +} + +BOOST_AUTO_TEST_CASE(testBufferGrow) +{ + Buffer buf; + buf.append(string(400, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 400); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); + + buf.retrieve(50); + BOOST_CHECK_EQUAL(buf.readableBytes(), 350); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); + + buf.append(string(1000, 'z')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 1350); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); // FIXME + + buf.retrieveAll(); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), 1400); // FIXME + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferInsideGrow) +{ + Buffer buf; + buf.append(string(800, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 800); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); + + buf.retrieve(500); + BOOST_CHECK_EQUAL(buf.readableBytes(), 300); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+500); + + buf.append(string(300, 'z')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 600); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-600); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferShrink) +{ + Buffer buf; + buf.append(string(2000, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 2000); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + buf.retrieve(1500); + BOOST_CHECK_EQUAL(buf.readableBytes(), 500); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+1500); + + buf.shrink(0); + BOOST_CHECK_EQUAL(buf.readableBytes(), 500); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-500); + BOOST_CHECK_EQUAL(buf.retrieveAllAsString(), string(500, 'y')); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferPrepend) +{ + Buffer buf; + buf.append(string(200, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 200); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + int x = 0; + buf.prepend(&x, sizeof x); + BOOST_CHECK_EQUAL(buf.readableBytes(), 204); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend - 4); +} + +BOOST_AUTO_TEST_CASE(testBufferReadInt) +{ + Buffer buf; + buf.append("HTTP"); + + BOOST_CHECK_EQUAL(buf.readableBytes(), 4); + BOOST_CHECK_EQUAL(buf.peekInt8(), 'H'); + int top16 = buf.peekInt16(); + BOOST_CHECK_EQUAL(top16, 'H'*256 + 'T'); + BOOST_CHECK_EQUAL(buf.peekInt32(), top16*65536 + 'T'*256 + 'P'); + + BOOST_CHECK_EQUAL(buf.readInt8(), 'H'); + BOOST_CHECK_EQUAL(buf.readInt16(), 'T'*256 + 'T'); + BOOST_CHECK_EQUAL(buf.readInt8(), 'P'); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + + buf.appendInt8(-1); + buf.appendInt16(-2); + buf.appendInt32(-3); + BOOST_CHECK_EQUAL(buf.readableBytes(), 7); + BOOST_CHECK_EQUAL(buf.readInt8(), -1); + BOOST_CHECK_EQUAL(buf.readInt16(), -2); + BOOST_CHECK_EQUAL(buf.readInt32(), -3); +} + +BOOST_AUTO_TEST_CASE(testBufferFindEOL) +{ + Buffer buf; + buf.append(string(100000, 'x')); + const char* null = NULL; + BOOST_CHECK_EQUAL(buf.findEOL(), null); + BOOST_CHECK_EQUAL(buf.findEOL(buf.peek()+90000), null); +} + +void output(Buffer&& buf, const void* inner) +{ + Buffer newbuf(std::move(buf)); + // printf("New Buffer at %p, inner %p\n", &newbuf, newbuf.peek()); + BOOST_CHECK_EQUAL(inner, newbuf.peek()); +} + +// NOTE: This test fails in g++ 4.4, passes in g++ 4.6. +BOOST_AUTO_TEST_CASE(testMove) +{ + Buffer buf; + buf.append("muduo", 5); + const void* inner = buf.peek(); + // printf("Buffer at %p, inner %p\n", &buf, inner); + output(std::move(buf), inner); +} diff --git a/include/muduo/net/tests/CMakeLists.txt b/include/muduo/net/tests/CMakeLists.txt new file mode 100644 index 0000000..a7aa3a0 --- /dev/null +++ b/include/muduo/net/tests/CMakeLists.txt @@ -0,0 +1,48 @@ +add_executable(channel_test Channel_test.cc) +target_link_libraries(channel_test muduo_net) + +add_executable(echoserver_unittest EchoServer_unittest.cc) +target_link_libraries(echoserver_unittest muduo_net) + +add_executable(echoclient_unittest EchoClient_unittest.cc) +target_link_libraries(echoclient_unittest muduo_net) + +add_executable(eventloop_unittest EventLoop_unittest.cc) +target_link_libraries(eventloop_unittest muduo_net) + +add_executable(eventloopthread_unittest EventLoopThread_unittest.cc) +target_link_libraries(eventloopthread_unittest muduo_net) + +add_executable(eventloopthreadpool_unittest EventLoopThreadPool_unittest.cc) +target_link_libraries(eventloopthreadpool_unittest muduo_net) + +if(BOOSTTEST_LIBRARY) +add_executable(buffer_unittest Buffer_unittest.cc) +target_link_libraries(buffer_unittest muduo_net boost_unit_test_framework) +add_test(NAME buffer_unittest COMMAND buffer_unittest) + +add_executable(inetaddress_unittest InetAddress_unittest.cc) +target_link_libraries(inetaddress_unittest muduo_net boost_unit_test_framework) +add_test(NAME inetaddress_unittest COMMAND inetaddress_unittest) + +if(ZLIB_FOUND) + add_executable(zlibstream_unittest ZlibStream_unittest.cc) + target_link_libraries(zlibstream_unittest muduo_net boost_unit_test_framework z) + # set_target_properties(zlibstream_unittest PROPERTIES COMPILE_FLAGS "-std=c++0x") +endif() + +endif() + +add_executable(tcpclient_reg1 TcpClient_reg1.cc) +target_link_libraries(tcpclient_reg1 muduo_net) + +add_executable(tcpclient_reg2 TcpClient_reg2.cc) +target_link_libraries(tcpclient_reg2 muduo_net) + +add_executable(tcpclient_reg3 TcpClient_reg3.cc) +target_link_libraries(tcpclient_reg3 muduo_net) + +add_executable(timerqueue_unittest TimerQueue_unittest.cc) +target_link_libraries(timerqueue_unittest muduo_net) +add_test(NAME timerqueue_unittest COMMAND timerqueue_unittest) + diff --git a/include/muduo/net/tests/Channel_test.cc b/include/muduo/net/tests/Channel_test.cc new file mode 100644 index 0000000..6276531 --- /dev/null +++ b/include/muduo/net/tests/Channel_test.cc @@ -0,0 +1,112 @@ +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" + +#include +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(const char* msg) +{ + static std::map lasts; + Timestamp& last = lasts[msg]; + Timestamp now = Timestamp::now(); + printf("%s tid %d %s delay %f\n", now.toString().c_str(), CurrentThread::tid(), + msg, timeDifference(now, last)); + last = now; +} + +namespace muduo +{ +namespace net +{ +namespace detail +{ +int createTimerfd(); +void readTimerfd(int timerfd, Timestamp now); +} +} +} + +// Use relative time, immunized to wall clock changes. +class PeriodicTimer +{ + public: + PeriodicTimer(EventLoop* loop, double interval, const TimerCallback& cb) + : loop_(loop), + timerfd_(muduo::net::detail::createTimerfd()), + timerfdChannel_(loop, timerfd_), + interval_(interval), + cb_(cb) + { + timerfdChannel_.setReadCallback( + std::bind(&PeriodicTimer::handleRead, this)); + timerfdChannel_.enableReading(); + } + + void start() + { + struct itimerspec spec; + memZero(&spec, sizeof spec); + spec.it_interval = toTimeSpec(interval_); + spec.it_value = spec.it_interval; + int ret = ::timerfd_settime(timerfd_, 0 /* relative timer */, &spec, NULL); + if (ret) + { + LOG_SYSERR << "timerfd_settime()"; + } + } + + ~PeriodicTimer() + { + timerfdChannel_.disableAll(); + timerfdChannel_.remove(); + ::close(timerfd_); + } + + private: + void handleRead() + { + loop_->assertInLoopThread(); + muduo::net::detail::readTimerfd(timerfd_, Timestamp::now()); + if (cb_) + cb_(); + } + + static struct timespec toTimeSpec(double seconds) + { + struct timespec ts; + memZero(&ts, sizeof ts); + const int64_t kNanoSecondsPerSecond = 1000000000; + const int kMinInterval = 100000; + int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); + if (nanoseconds < kMinInterval) + nanoseconds = kMinInterval; + ts.tv_sec = static_cast(nanoseconds / kNanoSecondsPerSecond); + ts.tv_nsec = static_cast(nanoseconds % kNanoSecondsPerSecond); + return ts; + } + + EventLoop* loop_; + const int timerfd_; + Channel timerfdChannel_; + const double interval_; // in seconds + TimerCallback cb_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid() + << " Try adjusting the wall clock, see what happens."; + EventLoop loop; + PeriodicTimer timer(&loop, 1, std::bind(print, "PeriodicTimer")); + timer.start(); + loop.runEvery(1, std::bind(print, "EventLoop::runEvery")); + loop.loop(); +} diff --git a/include/muduo/net/tests/EchoClient_unittest.cc b/include/muduo/net/tests/EchoClient_unittest.cc new file mode 100644 index 0000000..44d973a --- /dev/null +++ b/include/muduo/net/tests/EchoClient_unittest.cc @@ -0,0 +1,114 @@ +#include "muduo/net/TcpClient.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; +class EchoClient; +std::vector> clients; +int current = 0; + +class EchoClient : noncopyable +{ + public: + EchoClient(EventLoop* loop, const InetAddress& listenAddr, const string& id) + : loop_(loop), + client_(loop, listenAddr, "EchoClient"+id) + { + client_.setConnectionCallback( + std::bind(&EchoClient::onConnection, this, _1)); + client_.setMessageCallback( + std::bind(&EchoClient::onMessage, this, _1, _2, _3)); + //client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + // void stop(); + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->localAddress().toIpPort() << " -> " + << conn->peerAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + if (conn->connected()) + { + ++current; + if (implicit_cast(current) < clients.size()) + { + clients[current]->connect(); + } + LOG_INFO << "*** connected " << current; + } + conn->send("world\n"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + string msg(buf->retrieveAllAsString()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); + if (msg == "quit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + else if (msg == "shutdown\n") + { + loop_->quit(); + } + else + { + conn->send(msg); + } + } + + EventLoop* loop_; + TcpClient client_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 1) + { + EventLoop loop; + bool ipv6 = argc > 3; + InetAddress serverAddr(argv[1], 2000, ipv6); + + int n = 1; + if (argc > 2) + { + n = atoi(argv[2]); + } + + clients.reserve(n); + for (int i = 0; i < n; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "%d", i+1); + clients.emplace_back(new EchoClient(&loop, serverAddr, buf)); + } + + clients[current]->connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip [current#]\n", argv[0]); + } +} + diff --git a/include/muduo/net/tests/EchoServer_unittest.cc b/include/muduo/net/tests/EchoServer_unittest.cc new file mode 100644 index 0000000..0875668 --- /dev/null +++ b/include/muduo/net/tests/EchoServer_unittest.cc @@ -0,0 +1,86 @@ +#include "muduo/net/TcpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; + +class EchoServer +{ + public: + EchoServer(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "EchoServer") + { + server_.setConnectionCallback( + std::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + std::bind(&EchoServer::onMessage, this, _1, _2, _3)); + server_.setThreadNum(numThreads); + } + + void start() + { + server_.start(); + } + // void stop(); + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->peerAddress().toIpPort() << " -> " + << conn->localAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + LOG_INFO << conn->getTcpInfoString(); + + conn->send("hello\n"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + string msg(buf->retrieveAllAsString()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); + if (msg == "exit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + if (msg == "quit\n") + { + loop_->quit(); + } + conn->send(msg); + } + + EventLoop* loop_; + TcpServer server_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); + if (argc > 1) + { + numThreads = atoi(argv[1]); + } + bool ipv6 = argc > 2; + EventLoop loop; + InetAddress listenAddr(2000, false, ipv6); + EchoServer server(&loop, listenAddr); + + server.start(); + + loop.loop(); +} + diff --git a/include/muduo/net/tests/EventLoopThreadPool_unittest.cc b/include/muduo/net/tests/EventLoopThreadPool_unittest.cc new file mode 100644 index 0000000..1bf1bd3 --- /dev/null +++ b/include/muduo/net/tests/EventLoopThreadPool_unittest.cc @@ -0,0 +1,68 @@ +#include "muduo/net/EventLoopThreadPool.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(EventLoop* p = NULL) +{ + printf("main(): pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +void init(EventLoop* p) +{ + printf("init(): pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +int main() +{ + print(); + + EventLoop loop; + loop.runAfter(11, std::bind(&EventLoop::quit, &loop)); + + { + printf("Single thread %p:\n", &loop); + EventLoopThreadPool model(&loop, "single"); + model.setThreadNum(0); + model.start(init); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + } + + { + printf("Another thread:\n"); + EventLoopThreadPool model(&loop, "another"); + model.setThreadNum(1); + model.start(init); + EventLoop* nextLoop = model.getNextLoop(); + nextLoop->runAfter(2, std::bind(print, nextLoop)); + assert(nextLoop != &loop); + assert(nextLoop == model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + ::sleep(3); + } + + { + printf("Three threads:\n"); + EventLoopThreadPool model(&loop, "three"); + model.setThreadNum(3); + model.start(init); + EventLoop* nextLoop = model.getNextLoop(); + nextLoop->runInLoop(std::bind(print, nextLoop)); + assert(nextLoop != &loop); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + } + + loop.loop(); +} + diff --git a/include/muduo/net/tests/EventLoopThread_unittest.cc b/include/muduo/net/tests/EventLoopThread_unittest.cc new file mode 100644 index 0000000..d67c128 --- /dev/null +++ b/include/muduo/net/tests/EventLoopThread_unittest.cc @@ -0,0 +1,48 @@ +#include "muduo/net/EventLoopThread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" +#include "muduo/base/CountDownLatch.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(EventLoop* p = NULL) +{ + printf("print: pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +void quit(EventLoop* p) +{ + print(p); + p->quit(); +} + +int main() +{ + print(); + + { + EventLoopThread thr1; // never start + } + + { + // dtor calls quit() + EventLoopThread thr2; + EventLoop* loop = thr2.startLoop(); + loop->runInLoop(std::bind(print, loop)); + CurrentThread::sleepUsec(500 * 1000); + } + + { + // quit() before dtor + EventLoopThread thr3; + EventLoop* loop = thr3.startLoop(); + loop->runInLoop(std::bind(quit, loop)); + CurrentThread::sleepUsec(500 * 1000); + } +} + diff --git a/include/muduo/net/tests/EventLoop_unittest.cc b/include/muduo/net/tests/EventLoop_unittest.cc new file mode 100644 index 0000000..6cb6d7d --- /dev/null +++ b/include/muduo/net/tests/EventLoop_unittest.cc @@ -0,0 +1,42 @@ +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +EventLoop* g_loop; + +void callback() +{ + printf("callback(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + EventLoop anotherLoop; +} + +void threadFunc() +{ + printf("threadFunc(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + + assert(EventLoop::getEventLoopOfCurrentThread() == NULL); + EventLoop loop; + assert(EventLoop::getEventLoopOfCurrentThread() == &loop); + loop.runAfter(1.0, callback); + loop.loop(); +} + +int main() +{ + printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + + assert(EventLoop::getEventLoopOfCurrentThread() == NULL); + EventLoop loop; + assert(EventLoop::getEventLoopOfCurrentThread() == &loop); + + Thread thread(threadFunc); + thread.start(); + + loop.loop(); +} diff --git a/include/muduo/net/tests/InetAddress_unittest.cc b/include/muduo/net/tests/InetAddress_unittest.cc new file mode 100644 index 0000000..bdd31e0 --- /dev/null +++ b/include/muduo/net/tests/InetAddress_unittest.cc @@ -0,0 +1,70 @@ +#include "muduo/net/InetAddress.h" + +#include "muduo/base/Logging.h" + +//#define BOOST_TEST_MODULE InetAddressTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::net::InetAddress; + +BOOST_AUTO_TEST_CASE(testInetAddress) +{ + InetAddress addr0(1234); + BOOST_CHECK_EQUAL(addr0.toIp(), string("0.0.0.0")); + BOOST_CHECK_EQUAL(addr0.toIpPort(), string("0.0.0.0:1234")); + BOOST_CHECK_EQUAL(addr0.port(), 1234); + + InetAddress addr1(4321, true); + BOOST_CHECK_EQUAL(addr1.toIp(), string("127.0.0.1")); + BOOST_CHECK_EQUAL(addr1.toIpPort(), string("127.0.0.1:4321")); + BOOST_CHECK_EQUAL(addr1.port(), 4321); + + InetAddress addr2("1.2.3.4", 8888); + BOOST_CHECK_EQUAL(addr2.toIp(), string("1.2.3.4")); + BOOST_CHECK_EQUAL(addr2.toIpPort(), string("1.2.3.4:8888")); + BOOST_CHECK_EQUAL(addr2.port(), 8888); + + InetAddress addr3("255.254.253.252", 65535); + BOOST_CHECK_EQUAL(addr3.toIp(), string("255.254.253.252")); + BOOST_CHECK_EQUAL(addr3.toIpPort(), string("255.254.253.252:65535")); + BOOST_CHECK_EQUAL(addr3.port(), 65535); +} + +BOOST_AUTO_TEST_CASE(testInet6Address) +{ + InetAddress addr0(1234, false, true); + BOOST_CHECK_EQUAL(addr0.toIp(), string("::")); + BOOST_CHECK_EQUAL(addr0.toIpPort(), string("[::]:1234")); + BOOST_CHECK_EQUAL(addr0.port(), 1234); + + InetAddress addr1(1234, true, true); + BOOST_CHECK_EQUAL(addr1.toIp(), string("::1")); + BOOST_CHECK_EQUAL(addr1.toIpPort(), string("[::1]:1234")); + BOOST_CHECK_EQUAL(addr1.port(), 1234); + + InetAddress addr2("2001:db8::1", 8888, true); + BOOST_CHECK_EQUAL(addr2.toIp(), string("2001:db8::1")); + BOOST_CHECK_EQUAL(addr2.toIpPort(), string("[2001:db8::1]:8888")); + BOOST_CHECK_EQUAL(addr2.port(), 8888); + + InetAddress addr3("fe80::1234:abcd:1", 8888); + BOOST_CHECK_EQUAL(addr3.toIp(), string("fe80::1234:abcd:1")); + BOOST_CHECK_EQUAL(addr3.toIpPort(), string("[fe80::1234:abcd:1]:8888")); + BOOST_CHECK_EQUAL(addr3.port(), 8888); +} + +BOOST_AUTO_TEST_CASE(testInetAddressResolve) +{ + InetAddress addr(80); + if (InetAddress::resolve("google.com", &addr)) + { + LOG_INFO << "google.com resolved to " << addr.toIpPort(); + } + else + { + LOG_ERROR << "Unable to resolve google.com"; + } +} diff --git a/include/muduo/net/tests/TcpClient_reg1.cc b/include/muduo/net/tests/TcpClient_reg1.cc new file mode 100644 index 0000000..41b76b2 --- /dev/null +++ b/include/muduo/net/tests/TcpClient_reg1.cc @@ -0,0 +1,29 @@ +// TcpClient::stop() called in the same iteration of IO event + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +TcpClient* g_client; + +void timeout() +{ + LOG_INFO << "timeout"; + g_client->stop(); +} + +int main(int argc, char* argv[]) +{ + EventLoop loop; + InetAddress serverAddr("127.0.0.1", 2); // no such server + TcpClient client(&loop, serverAddr, "TcpClient"); + g_client = &client; + loop.runAfter(0.0, timeout); + loop.runAfter(1.0, std::bind(&EventLoop::quit, &loop)); + client.connect(); + CurrentThread::sleepUsec(100 * 1000); + loop.loop(); +} diff --git a/include/muduo/net/tests/TcpClient_reg2.cc b/include/muduo/net/tests/TcpClient_reg2.cc new file mode 100644 index 0000000..1637dbd --- /dev/null +++ b/include/muduo/net/tests/TcpClient_reg2.cc @@ -0,0 +1,30 @@ +// TcpClient destructs when TcpConnection is connected but unique. + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +void threadFunc(EventLoop* loop) +{ + InetAddress serverAddr("127.0.0.1", 1234); // should succeed + TcpClient client(loop, serverAddr, "TcpClient"); + client.connect(); + + CurrentThread::sleepUsec(1000*1000); + // client destructs when connected. +} + +int main(int argc, char* argv[]) +{ + Logger::setLogLevel(Logger::DEBUG); + + EventLoop loop; + loop.runAfter(3.0, std::bind(&EventLoop::quit, &loop)); + Thread thr(std::bind(threadFunc, &loop)); + thr.start(); + loop.loop(); +} diff --git a/include/muduo/net/tests/TcpClient_reg3.cc b/include/muduo/net/tests/TcpClient_reg3.cc new file mode 100644 index 0000000..bb1e5ee --- /dev/null +++ b/include/muduo/net/tests/TcpClient_reg3.cc @@ -0,0 +1,24 @@ +// TcpClient destructs in a different thread. + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoopThread.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +int main(int argc, char* argv[]) +{ + Logger::setLogLevel(Logger::DEBUG); + + EventLoopThread loopThread; + { + InetAddress serverAddr("127.0.0.1", 1234); // should succeed + TcpClient client(loopThread.startLoop(), serverAddr, "TcpClient"); + client.connect(); + CurrentThread::sleepUsec(500 * 1000); // wait for connect + client.disconnect(); + } + + CurrentThread::sleepUsec(1000 * 1000); +} diff --git a/include/muduo/net/tests/TimerQueue_unittest.cc b/include/muduo/net/tests/TimerQueue_unittest.cc new file mode 100644 index 0000000..65cff93 --- /dev/null +++ b/include/muduo/net/tests/TimerQueue_unittest.cc @@ -0,0 +1,66 @@ +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" +#include "muduo/base/Thread.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int cnt = 0; +EventLoop* g_loop; + +void printTid() +{ + printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + printf("now %s\n", Timestamp::now().toString().c_str()); +} + +void print(const char* msg) +{ + printf("msg %s %s\n", Timestamp::now().toString().c_str(), msg); + if (++cnt == 20) + { + g_loop->quit(); + } +} + +void cancel(TimerId timer) +{ + g_loop->cancel(timer); + printf("cancelled at %s\n", Timestamp::now().toString().c_str()); +} + +int main() +{ + printTid(); + sleep(1); + { + EventLoop loop; + g_loop = &loop; + + print("main"); + loop.runAfter(1, std::bind(print, "once1")); + loop.runAfter(1.5, std::bind(print, "once1.5")); + loop.runAfter(2.5, std::bind(print, "once2.5")); + loop.runAfter(3.5, std::bind(print, "once3.5")); + TimerId t45 = loop.runAfter(4.5, std::bind(print, "once4.5")); + loop.runAfter(4.2, std::bind(cancel, t45)); + loop.runAfter(4.8, std::bind(cancel, t45)); + loop.runEvery(2, std::bind(print, "every2")); + TimerId t3 = loop.runEvery(3, std::bind(print, "every3")); + loop.runAfter(9.001, std::bind(cancel, t3)); + + loop.loop(); + print("main loop exits"); + } + sleep(1); + { + EventLoopThread loopThread; + EventLoop* loop = loopThread.startLoop(); + loop->runAfter(2, printTid); + sleep(3); + print("thread loop exits"); + } +} diff --git a/include/muduo/net/tests/ZlibStream_unittest.cc b/include/muduo/net/tests/ZlibStream_unittest.cc new file mode 100644 index 0000000..144dda0 --- /dev/null +++ b/include/muduo/net/tests/ZlibStream_unittest.cc @@ -0,0 +1,91 @@ +#include "muduo/net/ZlibStream.h" + +#include "muduo/base/Logging.h" + +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +#include + +BOOST_AUTO_TEST_CASE(testZlibOutputStream) +{ + muduo::net::Buffer output; + { + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(output.readableBytes(), 0); + } + BOOST_CHECK_EQUAL(output.readableBytes(), 8); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream1) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + stream.finish(); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream2) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); + stream.finish(); + // printf("%zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream3) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + for (int i = 0; i < 1024*1024; ++i) + { + BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); + } + stream.finish(); + // printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream4) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + muduo::string input; + for (int i = 0; i < 32768; ++i) + { + input += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-"[rand() % 64]; + } + + for (int i = 0; i < 10; ++i) + { + BOOST_CHECK(stream.write(input)); + } + stream.finish(); + // printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream5) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + muduo::string input(1024*1024, '_'); + for (int i = 0; i < 64; ++i) + { + BOOST_CHECK(stream.write(input)); + } + printf("bufsiz %d\n", stream.internalOutputBufferSize()); + LOG_INFO << "total_in " << stream.inputBytes(); + LOG_INFO << "total_out " << stream.outputBytes(); + stream.finish(); + printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} From ba0ae7e50f77f06a7e180f29d1590d9fa457c21d Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 Date: Mon, 17 May 2021 01:05:54 +0800 Subject: [PATCH 09/16] update need a lot to improve --- .idea/.gitignore | 8 + .idea/.name | 1 + .idea/cids-server.iml | 2 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + cmake-build-debug/CMakeCache.txt | 423 +++++++++++ .../CMakeFiles/3.19.2/CMakeCCompiler.cmake | 77 ++ .../CMakeFiles/3.19.2/CMakeCXXCompiler.cmake | 89 +++ .../3.19.2/CMakeDetermineCompilerABI_C.bin | Bin 0 -> 53904 bytes .../3.19.2/CMakeDetermineCompilerABI_CXX.bin | Bin 0 -> 53913 bytes .../CMakeFiles/3.19.2/CMakeRCCompiler.cmake | 6 + .../CMakeFiles/3.19.2/CMakeSystem.cmake | 15 + .../3.19.2/CompilerIdC/CMakeCCompilerId.c | 691 ++++++++++++++++++ .../CMakeFiles/3.19.2/CompilerIdC/a.exe | Bin 0 -> 54020 bytes .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 680 +++++++++++++++++ .../CMakeFiles/3.19.2/CompilerIdCXX/a.exe | Bin 0 -> 54048 bytes cmake-build-debug/CMakeFiles/CMakeOutput.log | 498 +++++++++++++ .../CMakeFiles/clion-environment.txt | 4 + cmake-build-debug/CMakeFiles/clion-log.txt | 32 + .../CMakeFiles/cmake.check_cache | 1 + include/db_control/db_control.cpp | 57 ++ include/mirror/ClassInfo.h | 12 - include/mirror/ClassInfo.hpp | 18 + include/mirror/Cli.cpp | 5 + include/mirror/Cli.hpp | 15 + include/mirror/{Message.h => Message.hpp} | 14 +- include/mirror/Mirror.cpp | 225 ++++++ include/mirror/Mirror.h | 33 - include/mirror/Mirror.hpp | 58 ++ include/mirror/MirrorConfig.txt | 6 +- include/mirror/lesson.hpp | 22 + 32 files changed, 2956 insertions(+), 54 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/cids-server.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 cmake-build-debug/CMakeCache.txt create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CMakeCCompiler.cmake create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CMakeCXXCompiler.cmake create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_C.bin create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_CXX.bin create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CMakeRCCompiler.cmake create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CMakeSystem.cmake create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/CMakeCCompilerId.c create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100644 cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe create mode 100644 cmake-build-debug/CMakeFiles/CMakeOutput.log create mode 100644 cmake-build-debug/CMakeFiles/clion-environment.txt create mode 100644 cmake-build-debug/CMakeFiles/clion-log.txt create mode 100644 cmake-build-debug/CMakeFiles/cmake.check_cache create mode 100644 include/db_control/db_control.cpp delete mode 100644 include/mirror/ClassInfo.h create mode 100644 include/mirror/ClassInfo.hpp create mode 100644 include/mirror/Cli.cpp create mode 100644 include/mirror/Cli.hpp rename include/mirror/{Message.h => Message.hpp} (55%) create mode 100644 include/mirror/Mirror.cpp delete mode 100644 include/mirror/Mirror.h create mode 100644 include/mirror/Mirror.hpp create mode 100644 include/mirror/lesson.hpp diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..c7e59f5 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +pro \ No newline at end of file diff --git a/.idea/cids-server.iml b/.idea/cids-server.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/cids-server.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..424a3a2 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/cmake-build-debug/CMakeCache.txt b/cmake-build-debug/CMakeCache.txt new file mode 100644 index 0000000..1962d1a --- /dev/null +++ b/cmake-build-debug/CMakeCache.txt @@ -0,0 +1,423 @@ +# This is the CMakeCache file. +# For build in directory: d:/2021_2/cids-server/cmake-build-debug +# It was generated by CMake: C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/cmake.exe +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_ADDR2LINE:FILEPATH=C:/BC/C/mingw64/bin/addr2line.exe + +//Path to a program. +CMAKE_AR:FILEPATH=C:/BC/C/mingw64/bin/ar.exe + +//Choose the type of build, options are: None Debug Release RelWithDebInfo +// MinSizeRel ... +CMAKE_BUILD_TYPE:STRING=Debug + +//Id string of the compiler for the CodeBlocks IDE. Automatically +// detected when left empty +CMAKE_CODEBLOCKS_COMPILER_ID:STRING= + +//The CodeBlocks executable +CMAKE_CODEBLOCKS_EXECUTABLE:FILEPATH=CMAKE_CODEBLOCKS_EXECUTABLE-NOTFOUND + +//Additional command line arguments when CodeBlocks invokes make. +// Enter e.g. -j to get parallel builds +CMAKE_CODEBLOCKS_MAKE_ARGUMENTS:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler +CMAKE_CXX_COMPILER:FILEPATH=C:/BC/C/mingw64/bin/g++.exe + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_AR:FILEPATH=C:/BC/C/mingw64/bin/gcc-ar.exe + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_RANLIB:FILEPATH=C:/BC/C/mingw64/bin/gcc-ranlib.exe + +//Flags used by the CXX compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the CXX compiler during DEBUG builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the CXX compiler during MINSIZEREL builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the CXX compiler during RELEASE builds. +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the CXX compiler during RELWITHDEBINFO builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Libraries linked by default with all C++ applications. +CMAKE_CXX_STANDARD_LIBRARIES:STRING=-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 + +//C compiler +CMAKE_C_COMPILER:FILEPATH=C:/BC/C/mingw64/bin/gcc.exe + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_AR:FILEPATH=C:/BC/C/mingw64/bin/gcc-ar.exe + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_RANLIB:FILEPATH=C:/BC/C/mingw64/bin/gcc-ranlib.exe + +//Flags used by the C compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the C compiler during DEBUG builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the C compiler during MINSIZEREL builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the C compiler during RELEASE builds. +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the C compiler during RELWITHDEBINFO builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Libraries linked by default with all C applications. +CMAKE_C_STANDARD_LIBRARIES:STRING=-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 + +//Path to a program. +CMAKE_DLLTOOL:FILEPATH=C:/BC/C/mingw64/bin/dlltool.exe + +//Flags used by the linker during all build types. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during DEBUG builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during MINSIZEREL builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during RELEASE builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during RELWITHDEBINFO builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Convert GNU import libraries to MS format (requires Visual Studio) +CMAKE_GNUtoMS:BOOL=OFF + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=C:/Program Files (x86)/pro + +//Path to a program. +CMAKE_LINKER:FILEPATH=C:/BC/C/mingw64/bin/ld.exe + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=C:/BC/C/mingw64/bin/mingw32-make.exe + +//Flags used by the linker during the creation of modules during +// all build types. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of modules during +// DEBUG builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of modules during +// MINSIZEREL builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of modules during +// RELEASE builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of modules during +// RELWITHDEBINFO builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=C:/BC/C/mingw64/bin/nm.exe + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=C:/BC/C/mingw64/bin/objcopy.exe + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=C:/BC/C/mingw64/bin/objdump.exe + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=pro + +//Path to a program. +CMAKE_RANLIB:FILEPATH=C:/BC/C/mingw64/bin/ranlib.exe + +//RC compiler +CMAKE_RC_COMPILER:FILEPATH=C:/BC/C/mingw64/bin/windres.exe + +//Flags for Windows Resource Compiler during all build types. +CMAKE_RC_FLAGS:STRING= + +//Flags for Windows Resource Compiler during DEBUG builds. +CMAKE_RC_FLAGS_DEBUG:STRING= + +//Flags for Windows Resource Compiler during MINSIZEREL builds. +CMAKE_RC_FLAGS_MINSIZEREL:STRING= + +//Flags for Windows Resource Compiler during RELEASE builds. +CMAKE_RC_FLAGS_RELEASE:STRING= + +//Flags for Windows Resource Compiler during RELWITHDEBINFO builds. +CMAKE_RC_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_READELF:FILEPATH=C:/BC/C/mingw64/bin/readelf.exe + +//Flags used by the linker during the creation of shared libraries +// during all build types. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of shared libraries +// during DEBUG builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of shared libraries +// during MINSIZEREL builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELEASE builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELWITHDEBINFO builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries +// during all build types. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of static libraries +// during DEBUG builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of static libraries +// during MINSIZEREL builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELEASE builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELWITHDEBINFO builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=C:/BC/C/mingw64/bin/strip.exe + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//The directory containing a CMake configuration file for RapidJSON. +RapidJSON_DIR:PATH=RapidJSON_DIR-NOTFOUND + +//Value Computed by CMake +pro_BINARY_DIR:STATIC=D:/2021_2/cids-server/cmake-build-debug + +//Value Computed by CMake +pro_SOURCE_DIR:STATIC=D:/2021_2/cids-server + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_ADDR2LINE +CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=d:/2021_2/cids-server/cmake-build-debug +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=19 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=2 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/cmake.exe +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/cpack.exe +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/ctest.exe +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR +CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB +CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_STANDARD_LIBRARIES +CMAKE_CXX_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_AR +CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB +CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_STANDARD_LIBRARIES +CMAKE_C_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_DLLTOOL +CMAKE_DLLTOOL-ADVANCED:INTERNAL=1 +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=Unknown +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL=CodeBlocks +//CXX compiler system defined macros +CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS:INTERNAL=__STDC__;1;__STDC_VERSION__;201710L;__STDC_UTF_16__;1;__STDC_UTF_32__;1;__STDC_HOSTED__;1;__GNUC__;8;__GNUC_MINOR__;1;__GNUC_PATCHLEVEL__;0;__VERSION__;"8.1.0";__ATOMIC_RELAXED;0;__ATOMIC_SEQ_CST;5;__ATOMIC_ACQUIRE;2;__ATOMIC_RELEASE;3;__ATOMIC_ACQ_REL;4;__ATOMIC_CONSUME;1;__pic__;1;__PIC__;1;__FINITE_MATH_ONLY__;0;__SIZEOF_INT__;4;__SIZEOF_LONG__;4;__SIZEOF_LONG_LONG__;8;__SIZEOF_SHORT__;2;__SIZEOF_FLOAT__;4;__SIZEOF_DOUBLE__;8;__SIZEOF_LONG_DOUBLE__;16;__SIZEOF_SIZE_T__;8;__CHAR_BIT__;8;__BIGGEST_ALIGNMENT__;16;__ORDER_LITTLE_ENDIAN__;1234;__ORDER_BIG_ENDIAN__;4321;__ORDER_PDP_ENDIAN__;3412;__BYTE_ORDER__;__ORDER_LITTLE_ENDIAN__;__FLOAT_WORD_ORDER__;__ORDER_LITTLE_ENDIAN__;__SIZEOF_POINTER__;8;__SIZE_TYPE__;long long unsigned int;__PTRDIFF_TYPE__;long long int;__WCHAR_TYPE__;short unsigned int;__WINT_TYPE__;short unsigned int;__INTMAX_TYPE__;long long int;__UINTMAX_TYPE__;long long unsigned int;__CHAR16_TYPE__;short unsigned int;__CHAR32_TYPE__;unsigned int;__SIG_ATOMIC_TYPE__;int;__INT8_TYPE__;signed char;__INT16_TYPE__;short int;__INT32_TYPE__;int;__INT64_TYPE__;long long int;__UINT8_TYPE__;unsigned char;__UINT16_TYPE__;short unsigned int;__UINT32_TYPE__;unsigned int;__UINT64_TYPE__;long long unsigned int;__INT_LEAST8_TYPE__;signed char;__INT_LEAST16_TYPE__;short int;__INT_LEAST32_TYPE__;int;__INT_LEAST64_TYPE__;long long int;__UINT_LEAST8_TYPE__;unsigned char;__UINT_LEAST16_TYPE__;short unsigned int;__UINT_LEAST32_TYPE__;unsigned int;__UINT_LEAST64_TYPE__;long long unsigned int;__INT_FAST8_TYPE__;signed char;__INT_FAST16_TYPE__;short int;__INT_FAST32_TYPE__;int;__INT_FAST64_TYPE__;long long int;__UINT_FAST8_TYPE__;unsigned char;__UINT_FAST16_TYPE__;short unsigned int;__UINT_FAST32_TYPE__;unsigned int;__UINT_FAST64_TYPE__;long long unsigned int;__INTPTR_TYPE__;long long int;__UINTPTR_TYPE__;long long unsigned int;__has_include(STR);__has_include__(STR);__has_include_next(STR);__has_include_next__(STR);__GXX_ABI_VERSION;1012;__SCHAR_MAX__;0x7f;__SHRT_MAX__;0x7fff;__INT_MAX__;0x7fffffff;__LONG_MAX__;0x7fffffffL;__LONG_LONG_MAX__;0x7fffffffffffffffLL;__WCHAR_MAX__;0xffff;__WCHAR_MIN__;0;__WINT_MAX__;0xffff;__WINT_MIN__;0;__PTRDIFF_MAX__;0x7fffffffffffffffLL;__SIZE_MAX__;0xffffffffffffffffULL;__SCHAR_WIDTH__;8;__SHRT_WIDTH__;16;__INT_WIDTH__;32;__LONG_WIDTH__;32;__LONG_LONG_WIDTH__;64;__WCHAR_WIDTH__;16;__WINT_WIDTH__;16;__PTRDIFF_WIDTH__;64;__SIZE_WIDTH__;64;__INTMAX_MAX__;0x7fffffffffffffffLL;__INTMAX_C(c);c ## LL;__UINTMAX_MAX__;0xffffffffffffffffULL;__UINTMAX_C(c);c ## ULL;__INTMAX_WIDTH__;64;__SIG_ATOMIC_MAX__;0x7fffffff;__SIG_ATOMIC_MIN__;(-__SIG_ATOMIC_MAX__ - 1);__SIG_ATOMIC_WIDTH__;32;__INT8_MAX__;0x7f;__INT16_MAX__;0x7fff;__INT32_MAX__;0x7fffffff;__INT64_MAX__;0x7fffffffffffffffLL;__UINT8_MAX__;0xff;__UINT16_MAX__;0xffff;__UINT32_MAX__;0xffffffffU;__UINT64_MAX__;0xffffffffffffffffULL;__INT_LEAST8_MAX__;0x7f;__INT8_C(c);c;__INT_LEAST8_WIDTH__;8;__INT_LEAST16_MAX__;0x7fff;__INT16_C(c);c;__INT_LEAST16_WIDTH__;16;__INT_LEAST32_MAX__;0x7fffffff;__INT32_C(c);c;__INT_LEAST32_WIDTH__;32;__INT_LEAST64_MAX__;0x7fffffffffffffffLL;__INT64_C(c);c ## LL;__INT_LEAST64_WIDTH__;64;__UINT_LEAST8_MAX__;0xff;__UINT8_C(c);c;__UINT_LEAST16_MAX__;0xffff;__UINT16_C(c);c;__UINT_LEAST32_MAX__;0xffffffffU;__UINT32_C(c);c ## U;__UINT_LEAST64_MAX__;0xffffffffffffffffULL;__UINT64_C(c);c ## ULL;__INT_FAST8_MAX__;0x7f;__INT_FAST8_WIDTH__;8;__INT_FAST16_MAX__;0x7fff;__INT_FAST16_WIDTH__;16;__INT_FAST32_MAX__;0x7fffffff;__INT_FAST32_WIDTH__;32;__INT_FAST64_MAX__;0x7fffffffffffffffLL;__INT_FAST64_WIDTH__;64;__UINT_FAST8_MAX__;0xff;__UINT_FAST16_MAX__;0xffff;__UINT_FAST32_MAX__;0xffffffffU;__UINT_FAST64_MAX__;0xffffffffffffffffULL;__INTPTR_MAX__;0x7fffffffffffffffLL;__INTPTR_WIDTH__;64;__UINTPTR_MAX__;0xffffffffffffffffULL;__GCC_IEC_559;2;__GCC_IEC_559_COMPLEX;2;__FLT_EVAL_METHOD__;0;__FLT_EVAL_METHOD_TS_18661_3__;0;__DEC_EVAL_METHOD__;2;__FLT_RADIX__;2;__FLT_MANT_DIG__;24;__FLT_DIG__;6;__FLT_MIN_EXP__;(-125);__FLT_MIN_10_EXP__;(-37);__FLT_MAX_EXP__;128;__FLT_MAX_10_EXP__;38;__FLT_DECIMAL_DIG__;9;__FLT_MAX__;3.40282346638528859811704183484516925e+38F;__FLT_MIN__;1.17549435082228750796873653722224568e-38F;__FLT_EPSILON__;1.19209289550781250000000000000000000e-7F;__FLT_DENORM_MIN__;1.40129846432481707092372958328991613e-45F;__FLT_HAS_DENORM__;1;__FLT_HAS_INFINITY__;1;__FLT_HAS_QUIET_NAN__;1;__DBL_MANT_DIG__;53;__DBL_DIG__;15;__DBL_MIN_EXP__;(-1021);__DBL_MIN_10_EXP__;(-307);__DBL_MAX_EXP__;1024;__DBL_MAX_10_EXP__;308;__DBL_DECIMAL_DIG__;17;__DBL_MAX__;((double)1.79769313486231570814527423731704357e+308L);__DBL_MIN__;((double)2.22507385850720138309023271733240406e-308L);__DBL_EPSILON__;((double)2.22044604925031308084726333618164062e-16L);__DBL_DENORM_MIN__;((double)4.94065645841246544176568792868221372e-324L);__DBL_HAS_DENORM__;1;__DBL_HAS_INFINITY__;1;__DBL_HAS_QUIET_NAN__;1;__LDBL_MANT_DIG__;64;__LDBL_DIG__;18;__LDBL_MIN_EXP__;(-16381);__LDBL_MIN_10_EXP__;(-4931);__LDBL_MAX_EXP__;16384;__LDBL_MAX_10_EXP__;4932;__DECIMAL_DIG__;21;__LDBL_DECIMAL_DIG__;21;__LDBL_MAX__;1.18973149535723176502126385303097021e+4932L;__LDBL_MIN__;3.36210314311209350626267781732175260e-4932L;__LDBL_EPSILON__;1.08420217248550443400745280086994171e-19L;__LDBL_DENORM_MIN__;3.64519953188247460252840593361941982e-4951L;__LDBL_HAS_DENORM__;1;__LDBL_HAS_INFINITY__;1;__LDBL_HAS_QUIET_NAN__;1;__FLT32_MANT_DIG__;24;__FLT32_DIG__;6;__FLT32_MIN_EXP__;(-125);__FLT32_MIN_10_EXP__;(-37);__FLT32_MAX_EXP__;128;__FLT32_MAX_10_EXP__;38;__FLT32_DECIMAL_DIG__;9;__FLT32_MAX__;3.40282346638528859811704183484516925e+38F32;__FLT32_MIN__;1.17549435082228750796873653722224568e-38F32;__FLT32_EPSILON__;1.19209289550781250000000000000000000e-7F32;__FLT32_DENORM_MIN__;1.40129846432481707092372958328991613e-45F32;__FLT32_HAS_DENORM__;1;__FLT32_HAS_INFINITY__;1;__FLT32_HAS_QUIET_NAN__;1;__FLT64_MANT_DIG__;53;__FLT64_DIG__;15;__FLT64_MIN_EXP__;(-1021);__FLT64_MIN_10_EXP__;(-307);__FLT64_MAX_EXP__;1024;__FLT64_MAX_10_EXP__;308;__FLT64_DECIMAL_DIG__;17;__FLT64_MAX__;1.79769313486231570814527423731704357e+308F64;__FLT64_MIN__;2.22507385850720138309023271733240406e-308F64;__FLT64_EPSILON__;2.22044604925031308084726333618164062e-16F64;__FLT64_DENORM_MIN__;4.94065645841246544176568792868221372e-324F64;__FLT64_HAS_DENORM__;1;__FLT64_HAS_INFINITY__;1;__FLT64_HAS_QUIET_NAN__;1;__FLT128_MANT_DIG__;113;__FLT128_DIG__;33;__FLT128_MIN_EXP__;(-16381);__FLT128_MIN_10_EXP__;(-4931);__FLT128_MAX_EXP__;16384;__FLT128_MAX_10_EXP__;4932;__FLT128_DECIMAL_DIG__;36;__FLT128_MAX__;1.18973149535723176508575932662800702e+4932F128;__FLT128_MIN__;3.36210314311209350626267781732175260e-4932F128;__FLT128_EPSILON__;1.92592994438723585305597794258492732e-34F128;__FLT128_DENORM_MIN__;6.47517511943802511092443895822764655e-4966F128;__FLT128_HAS_DENORM__;1;__FLT128_HAS_INFINITY__;1;__FLT128_HAS_QUIET_NAN__;1;__FLT32X_MANT_DIG__;53;__FLT32X_DIG__;15;__FLT32X_MIN_EXP__;(-1021);__FLT32X_MIN_10_EXP__;(-307);__FLT32X_MAX_EXP__;1024;__FLT32X_MAX_10_EXP__;308;__FLT32X_DECIMAL_DIG__;17;__FLT32X_MAX__;1.79769313486231570814527423731704357e+308F32x;__FLT32X_MIN__;2.22507385850720138309023271733240406e-308F32x;__FLT32X_EPSILON__;2.22044604925031308084726333618164062e-16F32x;__FLT32X_DENORM_MIN__;4.94065645841246544176568792868221372e-324F32x;__FLT32X_HAS_DENORM__;1;__FLT32X_HAS_INFINITY__;1;__FLT32X_HAS_QUIET_NAN__;1;__FLT64X_MANT_DIG__;64;__FLT64X_DIG__;18;__FLT64X_MIN_EXP__;(-16381);__FLT64X_MIN_10_EXP__;(-4931);__FLT64X_MAX_EXP__;16384;__FLT64X_MAX_10_EXP__;4932;__FLT64X_DECIMAL_DIG__;21;__FLT64X_MAX__;1.18973149535723176502126385303097021e+4932F64x;__FLT64X_MIN__;3.36210314311209350626267781732175260e-4932F64x;__FLT64X_EPSILON__;1.08420217248550443400745280086994171e-19F64x;__FLT64X_DENORM_MIN__;3.64519953188247460252840593361941982e-4951F64x;__FLT64X_HAS_DENORM__;1;__FLT64X_HAS_INFINITY__;1;__FLT64X_HAS_QUIET_NAN__;1;__DEC32_MANT_DIG__;7;__DEC32_MIN_EXP__;(-94);__DEC32_MAX_EXP__;97;__DEC32_MIN__;1E-95DF;__DEC32_MAX__;9.999999E96DF;__DEC32_EPSILON__;1E-6DF;__DEC32_SUBNORMAL_MIN__;0.000001E-95DF;__DEC64_MANT_DIG__;16;__DEC64_MIN_EXP__;(-382);__DEC64_MAX_EXP__;385;__DEC64_MIN__;1E-383DD;__DEC64_MAX__;9.999999999999999E384DD;__DEC64_EPSILON__;1E-15DD;__DEC64_SUBNORMAL_MIN__;0.000000000000001E-383DD;__DEC128_MANT_DIG__;34;__DEC128_MIN_EXP__;(-6142);__DEC128_MAX_EXP__;6145;__DEC128_MIN__;1E-6143DL;__DEC128_MAX__;9.999999999999999999999999999999999E6144DL;__DEC128_EPSILON__;1E-33DL;__DEC128_SUBNORMAL_MIN__;0.000000000000000000000000000000001E-6143DL;__REGISTER_PREFIX__; ;__USER_LABEL_PREFIX__; ;__GNUC_STDC_INLINE__;1;__NO_INLINE__;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16;1;__GCC_ATOMIC_BOOL_LOCK_FREE;2;__GCC_ATOMIC_CHAR_LOCK_FREE;2;__GCC_ATOMIC_CHAR16_T_LOCK_FREE;2;__GCC_ATOMIC_CHAR32_T_LOCK_FREE;2;__GCC_ATOMIC_WCHAR_T_LOCK_FREE;2;__GCC_ATOMIC_SHORT_LOCK_FREE;2;__GCC_ATOMIC_INT_LOCK_FREE;2;__GCC_ATOMIC_LONG_LOCK_FREE;2;__GCC_ATOMIC_LLONG_LOCK_FREE;2;__GCC_ATOMIC_TEST_AND_SET_TRUEVAL;1;__GCC_ATOMIC_POINTER_LOCK_FREE;2;__PRAGMA_REDEFINE_EXTNAME;1;__SIZEOF_INT128__;16;__SIZEOF_WCHAR_T__;2;__SIZEOF_WINT_T__;2;__SIZEOF_PTRDIFF_T__;8;__amd64;1;__amd64__;1;__x86_64;1;__x86_64__;1;__SIZEOF_FLOAT80__;16;__SIZEOF_FLOAT128__;16;__ATOMIC_HLE_ACQUIRE;65536;__ATOMIC_HLE_RELEASE;131072;__GCC_ASM_FLAG_OUTPUTS__;1;__nocona;1;__nocona__;1;__tune_core2__;1;__code_model_medium__;1;__MMX__;1;__SSE__;1;__SSE2__;1;__SSE3__;1;__FXSR__;1;__SSE_MATH__;1;__SSE2_MATH__;1;__SEG_FS;1;__SEG_GS;1;__SEH__;1;__stdcall;__attribute__((__stdcall__));__fastcall;__attribute__((__fastcall__));__thiscall;__attribute__((__thiscall__));__cdecl;__attribute__((__cdecl__));_stdcall;__attribute__((__stdcall__));_fastcall;__attribute__((__fastcall__));_thiscall;__attribute__((__thiscall__));_cdecl;__attribute__((__cdecl__));__GXX_MERGED_TYPEINFO_NAMES;0;__GXX_TYPEINFO_EQUALITY_INLINE;0;__MSVCRT__;1;__MINGW32__;1;_WIN32;1;__WIN32;1;__WIN32__;1;WIN32;1;__WINNT;1;__WINNT__;1;WINNT;1;_INTEGRAL_MAX_BITS;64;__MINGW64__;1;__WIN64;1;__WIN64__;1;WIN64;1;_WIN64;1;__declspec(x);__attribute__((x));__DECIMAL_BID_FORMAT__;1;_REENTRANT;1;__STDC__;1;__cplusplus;201402L;__STDC_UTF_16__;1;__STDC_UTF_32__;1;__STDC_HOSTED__;1;__GNUC__;8;__GNUC_MINOR__;1;__GNUC_PATCHLEVEL__;0;__VERSION__;"8.1.0";__ATOMIC_RELAXED;0;__ATOMIC_SEQ_CST;5;__ATOMIC_ACQUIRE;2;__ATOMIC_RELEASE;3;__ATOMIC_ACQ_REL;4;__ATOMIC_CONSUME;1;__pic__;1;__PIC__;1;__FINITE_MATH_ONLY__;0;__SIZEOF_INT__;4;__SIZEOF_LONG__;4;__SIZEOF_LONG_LONG__;8;__SIZEOF_SHORT__;2;__SIZEOF_FLOAT__;4;__SIZEOF_DOUBLE__;8;__SIZEOF_LONG_DOUBLE__;16;__SIZEOF_SIZE_T__;8;__CHAR_BIT__;8;__BIGGEST_ALIGNMENT__;16;__ORDER_LITTLE_ENDIAN__;1234;__ORDER_BIG_ENDIAN__;4321;__ORDER_PDP_ENDIAN__;3412;__BYTE_ORDER__;__ORDER_LITTLE_ENDIAN__;__FLOAT_WORD_ORDER__;__ORDER_LITTLE_ENDIAN__;__SIZEOF_POINTER__;8;__GNUG__;8;__SIZE_TYPE__;long long unsigned int;__PTRDIFF_TYPE__;long long int;__WCHAR_TYPE__;short unsigned int;__WINT_TYPE__;short unsigned int;__INTMAX_TYPE__;long long int;__UINTMAX_TYPE__;long long unsigned int;__CHAR16_TYPE__;short unsigned int;__CHAR32_TYPE__;unsigned int;__SIG_ATOMIC_TYPE__;int;__INT8_TYPE__;signed char;__INT16_TYPE__;short int;__INT32_TYPE__;int;__INT64_TYPE__;long long int;__UINT8_TYPE__;unsigned char;__UINT16_TYPE__;short unsigned int;__UINT32_TYPE__;unsigned int;__UINT64_TYPE__;long long unsigned int;__INT_LEAST8_TYPE__;signed char;__INT_LEAST16_TYPE__;short int;__INT_LEAST32_TYPE__;int;__INT_LEAST64_TYPE__;long long int;__UINT_LEAST8_TYPE__;unsigned char;__UINT_LEAST16_TYPE__;short unsigned int;__UINT_LEAST32_TYPE__;unsigned int;__UINT_LEAST64_TYPE__;long long unsigned int;__INT_FAST8_TYPE__;signed char;__INT_FAST16_TYPE__;short int;__INT_FAST32_TYPE__;int;__INT_FAST64_TYPE__;long long int;__UINT_FAST8_TYPE__;unsigned char;__UINT_FAST16_TYPE__;short unsigned int;__UINT_FAST32_TYPE__;unsigned int;__UINT_FAST64_TYPE__;long long unsigned int;__INTPTR_TYPE__;long long int;__UINTPTR_TYPE__;long long unsigned int;__has_include(STR);__has_include__(STR);__has_include_next(STR);__has_include_next__(STR);__GXX_WEAK__;1;__DEPRECATED;1;__GXX_RTTI;1;__cpp_rtti;199711;__GXX_EXPERIMENTAL_CXX0X__;1;__cpp_binary_literals;201304;__cpp_hex_float;201603;__cpp_runtime_arrays;198712;__cpp_unicode_characters;200704;__cpp_raw_strings;200710;__cpp_unicode_literals;200710;__cpp_user_defined_literals;200809;__cpp_lambdas;200907;__cpp_range_based_for;200907;__cpp_static_assert;200410;__cpp_decltype;200707;__cpp_attributes;200809;__cpp_rvalue_reference;200610;__cpp_rvalue_references;200610;__cpp_variadic_templates;200704;__cpp_initializer_lists;200806;__cpp_delegating_constructors;200604;__cpp_nsdmi;200809;__cpp_inheriting_constructors;201511;__cpp_ref_qualifiers;200710;__cpp_alias_templates;200704;__cpp_return_type_deduction;201304;__cpp_init_captures;201304;__cpp_generic_lambdas;201304;__cpp_constexpr;201304;__cpp_decltype_auto;201304;__cpp_aggregate_nsdmi;201304;__cpp_variable_templates;201304;__cpp_digit_separators;201309;__cpp_sized_deallocation;201309;__cpp_threadsafe_static_init;200806;__EXCEPTIONS;1;__cpp_exceptions;199711;__GXX_ABI_VERSION;1012;__SCHAR_MAX__;0x7f;__SHRT_MAX__;0x7fff;__INT_MAX__;0x7fffffff;__LONG_MAX__;0x7fffffffL;__LONG_LONG_MAX__;0x7fffffffffffffffLL;__WCHAR_MAX__;0xffff;__WCHAR_MIN__;0;__WINT_MAX__;0xffff;__WINT_MIN__;0;__PTRDIFF_MAX__;0x7fffffffffffffffLL;__SIZE_MAX__;0xffffffffffffffffULL;__SCHAR_WIDTH__;8;__SHRT_WIDTH__;16;__INT_WIDTH__;32;__LONG_WIDTH__;32;__LONG_LONG_WIDTH__;64;__WCHAR_WIDTH__;16;__WINT_WIDTH__;16;__PTRDIFF_WIDTH__;64;__SIZE_WIDTH__;64;__GLIBCXX_TYPE_INT_N_0;__int128;__GLIBCXX_BITSIZE_INT_N_0;128;__INTMAX_MAX__;0x7fffffffffffffffLL;__INTMAX_C(c);c ## LL;__UINTMAX_MAX__;0xffffffffffffffffULL;__UINTMAX_C(c);c ## ULL;__INTMAX_WIDTH__;64;__SIG_ATOMIC_MAX__;0x7fffffff;__SIG_ATOMIC_MIN__;(-__SIG_ATOMIC_MAX__ - 1);__SIG_ATOMIC_WIDTH__;32;__INT8_MAX__;0x7f;__INT16_MAX__;0x7fff;__INT32_MAX__;0x7fffffff;__INT64_MAX__;0x7fffffffffffffffLL;__UINT8_MAX__;0xff;__UINT16_MAX__;0xffff;__UINT32_MAX__;0xffffffffU;__UINT64_MAX__;0xffffffffffffffffULL;__INT_LEAST8_MAX__;0x7f;__INT8_C(c);c;__INT_LEAST8_WIDTH__;8;__INT_LEAST16_MAX__;0x7fff;__INT16_C(c);c;__INT_LEAST16_WIDTH__;16;__INT_LEAST32_MAX__;0x7fffffff;__INT32_C(c);c;__INT_LEAST32_WIDTH__;32;__INT_LEAST64_MAX__;0x7fffffffffffffffLL;__INT64_C(c);c ## LL;__INT_LEAST64_WIDTH__;64;__UINT_LEAST8_MAX__;0xff;__UINT8_C(c);c;__UINT_LEAST16_MAX__;0xffff;__UINT16_C(c);c;__UINT_LEAST32_MAX__;0xffffffffU;__UINT32_C(c);c ## U;__UINT_LEAST64_MAX__;0xffffffffffffffffULL;__UINT64_C(c);c ## ULL;__INT_FAST8_MAX__;0x7f;__INT_FAST8_WIDTH__;8;__INT_FAST16_MAX__;0x7fff;__INT_FAST16_WIDTH__;16;__INT_FAST32_MAX__;0x7fffffff;__INT_FAST32_WIDTH__;32;__INT_FAST64_MAX__;0x7fffffffffffffffLL;__INT_FAST64_WIDTH__;64;__UINT_FAST8_MAX__;0xff;__UINT_FAST16_MAX__;0xffff;__UINT_FAST32_MAX__;0xffffffffU;__UINT_FAST64_MAX__;0xffffffffffffffffULL;__INTPTR_MAX__;0x7fffffffffffffffLL;__INTPTR_WIDTH__;64;__UINTPTR_MAX__;0xffffffffffffffffULL;__GCC_IEC_559;2;__GCC_IEC_559_COMPLEX;2;__FLT_EVAL_METHOD__;0;__FLT_EVAL_METHOD_TS_18661_3__;0;__DEC_EVAL_METHOD__;2;__FLT_RADIX__;2;__FLT_MANT_DIG__;24;__FLT_DIG__;6;__FLT_MIN_EXP__;(-125);__FLT_MIN_10_EXP__;(-37);__FLT_MAX_EXP__;128;__FLT_MAX_10_EXP__;38;__FLT_DECIMAL_DIG__;9;__FLT_MAX__;3.40282346638528859811704183484516925e+38F;__FLT_MIN__;1.17549435082228750796873653722224568e-38F;__FLT_EPSILON__;1.19209289550781250000000000000000000e-7F;__FLT_DENORM_MIN__;1.40129846432481707092372958328991613e-45F;__FLT_HAS_DENORM__;1;__FLT_HAS_INFINITY__;1;__FLT_HAS_QUIET_NAN__;1;__DBL_MANT_DIG__;53;__DBL_DIG__;15;__DBL_MIN_EXP__;(-1021);__DBL_MIN_10_EXP__;(-307);__DBL_MAX_EXP__;1024;__DBL_MAX_10_EXP__;308;__DBL_DECIMAL_DIG__;17;__DBL_MAX__;double(1.79769313486231570814527423731704357e+308L);__DBL_MIN__;double(2.22507385850720138309023271733240406e-308L);__DBL_EPSILON__;double(2.22044604925031308084726333618164062e-16L);__DBL_DENORM_MIN__;double(4.94065645841246544176568792868221372e-324L);__DBL_HAS_DENORM__;1;__DBL_HAS_INFINITY__;1;__DBL_HAS_QUIET_NAN__;1;__LDBL_MANT_DIG__;64;__LDBL_DIG__;18;__LDBL_MIN_EXP__;(-16381);__LDBL_MIN_10_EXP__;(-4931);__LDBL_MAX_EXP__;16384;__LDBL_MAX_10_EXP__;4932;__DECIMAL_DIG__;21;__LDBL_DECIMAL_DIG__;21;__LDBL_MAX__;1.18973149535723176502126385303097021e+4932L;__LDBL_MIN__;3.36210314311209350626267781732175260e-4932L;__LDBL_EPSILON__;1.08420217248550443400745280086994171e-19L;__LDBL_DENORM_MIN__;3.64519953188247460252840593361941982e-4951L;__LDBL_HAS_DENORM__;1;__LDBL_HAS_INFINITY__;1;__LDBL_HAS_QUIET_NAN__;1;__FLT32_MANT_DIG__;24;__FLT32_DIG__;6;__FLT32_MIN_EXP__;(-125);__FLT32_MIN_10_EXP__;(-37);__FLT32_MAX_EXP__;128;__FLT32_MAX_10_EXP__;38;__FLT32_DECIMAL_DIG__;9;__FLT32_MAX__;3.40282346638528859811704183484516925e+38F32;__FLT32_MIN__;1.17549435082228750796873653722224568e-38F32;__FLT32_EPSILON__;1.19209289550781250000000000000000000e-7F32;__FLT32_DENORM_MIN__;1.40129846432481707092372958328991613e-45F32;__FLT32_HAS_DENORM__;1;__FLT32_HAS_INFINITY__;1;__FLT32_HAS_QUIET_NAN__;1;__FLT64_MANT_DIG__;53;__FLT64_DIG__;15;__FLT64_MIN_EXP__;(-1021);__FLT64_MIN_10_EXP__;(-307);__FLT64_MAX_EXP__;1024;__FLT64_MAX_10_EXP__;308;__FLT64_DECIMAL_DIG__;17;__FLT64_MAX__;1.79769313486231570814527423731704357e+308F64;__FLT64_MIN__;2.22507385850720138309023271733240406e-308F64;__FLT64_EPSILON__;2.22044604925031308084726333618164062e-16F64;__FLT64_DENORM_MIN__;4.94065645841246544176568792868221372e-324F64;__FLT64_HAS_DENORM__;1;__FLT64_HAS_INFINITY__;1;__FLT64_HAS_QUIET_NAN__;1;__FLT128_MANT_DIG__;113;__FLT128_DIG__;33;__FLT128_MIN_EXP__;(-16381);__FLT128_MIN_10_EXP__;(-4931);__FLT128_MAX_EXP__;16384;__FLT128_MAX_10_EXP__;4932;__FLT128_DECIMAL_DIG__;36;__FLT128_MAX__;1.18973149535723176508575932662800702e+4932F128;__FLT128_MIN__;3.36210314311209350626267781732175260e-4932F128;__FLT128_EPSILON__;1.92592994438723585305597794258492732e-34F128;__FLT128_DENORM_MIN__;6.47517511943802511092443895822764655e-4966F128;__FLT128_HAS_DENORM__;1;__FLT128_HAS_INFINITY__;1;__FLT128_HAS_QUIET_NAN__;1;__FLT32X_MANT_DIG__;53;__FLT32X_DIG__;15;__FLT32X_MIN_EXP__;(-1021);__FLT32X_MIN_10_EXP__;(-307);__FLT32X_MAX_EXP__;1024;__FLT32X_MAX_10_EXP__;308;__FLT32X_DECIMAL_DIG__;17;__FLT32X_MAX__;1.79769313486231570814527423731704357e+308F32x;__FLT32X_MIN__;2.22507385850720138309023271733240406e-308F32x;__FLT32X_EPSILON__;2.22044604925031308084726333618164062e-16F32x;__FLT32X_DENORM_MIN__;4.94065645841246544176568792868221372e-324F32x;__FLT32X_HAS_DENORM__;1;__FLT32X_HAS_INFINITY__;1;__FLT32X_HAS_QUIET_NAN__;1;__FLT64X_MANT_DIG__;64;__FLT64X_DIG__;18;__FLT64X_MIN_EXP__;(-16381);__FLT64X_MIN_10_EXP__;(-4931);__FLT64X_MAX_EXP__;16384;__FLT64X_MAX_10_EXP__;4932;__FLT64X_DECIMAL_DIG__;21;__FLT64X_MAX__;1.18973149535723176502126385303097021e+4932F64x;__FLT64X_MIN__;3.36210314311209350626267781732175260e-4932F64x;__FLT64X_EPSILON__;1.08420217248550443400745280086994171e-19F64x;__FLT64X_DENORM_MIN__;3.64519953188247460252840593361941982e-4951F64x;__FLT64X_HAS_DENORM__;1;__FLT64X_HAS_INFINITY__;1;__FLT64X_HAS_QUIET_NAN__;1;__DEC32_MANT_DIG__;7;__DEC32_MIN_EXP__;(-94);__DEC32_MAX_EXP__;97;__DEC32_MIN__;1E-95DF;__DEC32_MAX__;9.999999E96DF;__DEC32_EPSILON__;1E-6DF;__DEC32_SUBNORMAL_MIN__;0.000001E-95DF;__DEC64_MANT_DIG__;16;__DEC64_MIN_EXP__;(-382);__DEC64_MAX_EXP__;385;__DEC64_MIN__;1E-383DD;__DEC64_MAX__;9.999999999999999E384DD;__DEC64_EPSILON__;1E-15DD;__DEC64_SUBNORMAL_MIN__;0.000000000000001E-383DD;__DEC128_MANT_DIG__;34;__DEC128_MIN_EXP__;(-6142);__DEC128_MAX_EXP__;6145;__DEC128_MIN__;1E-6143DL;__DEC128_MAX__;9.999999999999999999999999999999999E6144DL;__DEC128_EPSILON__;1E-33DL;__DEC128_SUBNORMAL_MIN__;0.000000000000000000000000000000001E-6143DL;__REGISTER_PREFIX__; ;__USER_LABEL_PREFIX__; ;__GNUC_STDC_INLINE__;1;__NO_INLINE__;1;__WCHAR_UNSIGNED__;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16;1;__GCC_ATOMIC_BOOL_LOCK_FREE;2;__GCC_ATOMIC_CHAR_LOCK_FREE;2;__GCC_ATOMIC_CHAR16_T_LOCK_FREE;2;__GCC_ATOMIC_CHAR32_T_LOCK_FREE;2;__GCC_ATOMIC_WCHAR_T_LOCK_FREE;2;__GCC_ATOMIC_SHORT_LOCK_FREE;2;__GCC_ATOMIC_INT_LOCK_FREE;2;__GCC_ATOMIC_LONG_LOCK_FREE;2;__GCC_ATOMIC_LLONG_LOCK_FREE;2;__GCC_ATOMIC_TEST_AND_SET_TRUEVAL;1;__GCC_ATOMIC_POINTER_LOCK_FREE;2;__PRAGMA_REDEFINE_EXTNAME;1;__SIZEOF_INT128__;16;__SIZEOF_WCHAR_T__;2;__SIZEOF_WINT_T__;2;__SIZEOF_PTRDIFF_T__;8;__amd64;1;__amd64__;1;__x86_64;1;__x86_64__;1;__SIZEOF_FLOAT80__;16;__SIZEOF_FLOAT128__;16;__ATOMIC_HLE_ACQUIRE;65536;__ATOMIC_HLE_RELEASE;131072;__GCC_ASM_FLAG_OUTPUTS__;1;__nocona;1;__nocona__;1;__tune_core2__;1;__code_model_medium__;1;__MMX__;1;__SSE__;1;__SSE2__;1;__SSE3__;1;__FXSR__;1;__SSE_MATH__;1;__SSE2_MATH__;1;__SEG_FS;1;__SEG_GS;1;__SEH__;1;__stdcall;__attribute__((__stdcall__));__fastcall;__attribute__((__fastcall__));__thiscall;__attribute__((__thiscall__));__cdecl;__attribute__((__cdecl__));_stdcall;__attribute__((__stdcall__));_fastcall;__attribute__((__fastcall__));_thiscall;__attribute__((__thiscall__));_cdecl;__attribute__((__cdecl__));__GXX_MERGED_TYPEINFO_NAMES;0;__GXX_TYPEINFO_EQUALITY_INLINE;0;__MSVCRT__;1;__MINGW32__;1;_WIN32;1;__WIN32;1;__WIN32__;1;WIN32;1;__WINNT;1;__WINNT__;1;WINNT;1;_INTEGRAL_MAX_BITS;64;__MINGW64__;1;__WIN64;1;__WIN64__;1;WIN64;1;_WIN64;1;__declspec(x);__attribute__((x));__DECIMAL_BID_FORMAT__;1;_REENTRANT;1 +//CXX compiler system include directories +CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS:INTERNAL=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +//C compiler system defined macros +CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS:INTERNAL=__STDC__;1;__STDC_VERSION__;201710L;__STDC_UTF_16__;1;__STDC_UTF_32__;1;__STDC_HOSTED__;1;__GNUC__;8;__GNUC_MINOR__;1;__GNUC_PATCHLEVEL__;0;__VERSION__;"8.1.0";__ATOMIC_RELAXED;0;__ATOMIC_SEQ_CST;5;__ATOMIC_ACQUIRE;2;__ATOMIC_RELEASE;3;__ATOMIC_ACQ_REL;4;__ATOMIC_CONSUME;1;__pic__;1;__PIC__;1;__FINITE_MATH_ONLY__;0;__SIZEOF_INT__;4;__SIZEOF_LONG__;4;__SIZEOF_LONG_LONG__;8;__SIZEOF_SHORT__;2;__SIZEOF_FLOAT__;4;__SIZEOF_DOUBLE__;8;__SIZEOF_LONG_DOUBLE__;16;__SIZEOF_SIZE_T__;8;__CHAR_BIT__;8;__BIGGEST_ALIGNMENT__;16;__ORDER_LITTLE_ENDIAN__;1234;__ORDER_BIG_ENDIAN__;4321;__ORDER_PDP_ENDIAN__;3412;__BYTE_ORDER__;__ORDER_LITTLE_ENDIAN__;__FLOAT_WORD_ORDER__;__ORDER_LITTLE_ENDIAN__;__SIZEOF_POINTER__;8;__SIZE_TYPE__;long long unsigned int;__PTRDIFF_TYPE__;long long int;__WCHAR_TYPE__;short unsigned int;__WINT_TYPE__;short unsigned int;__INTMAX_TYPE__;long long int;__UINTMAX_TYPE__;long long unsigned int;__CHAR16_TYPE__;short unsigned int;__CHAR32_TYPE__;unsigned int;__SIG_ATOMIC_TYPE__;int;__INT8_TYPE__;signed char;__INT16_TYPE__;short int;__INT32_TYPE__;int;__INT64_TYPE__;long long int;__UINT8_TYPE__;unsigned char;__UINT16_TYPE__;short unsigned int;__UINT32_TYPE__;unsigned int;__UINT64_TYPE__;long long unsigned int;__INT_LEAST8_TYPE__;signed char;__INT_LEAST16_TYPE__;short int;__INT_LEAST32_TYPE__;int;__INT_LEAST64_TYPE__;long long int;__UINT_LEAST8_TYPE__;unsigned char;__UINT_LEAST16_TYPE__;short unsigned int;__UINT_LEAST32_TYPE__;unsigned int;__UINT_LEAST64_TYPE__;long long unsigned int;__INT_FAST8_TYPE__;signed char;__INT_FAST16_TYPE__;short int;__INT_FAST32_TYPE__;int;__INT_FAST64_TYPE__;long long int;__UINT_FAST8_TYPE__;unsigned char;__UINT_FAST16_TYPE__;short unsigned int;__UINT_FAST32_TYPE__;unsigned int;__UINT_FAST64_TYPE__;long long unsigned int;__INTPTR_TYPE__;long long int;__UINTPTR_TYPE__;long long unsigned int;__has_include(STR);__has_include__(STR);__has_include_next(STR);__has_include_next__(STR);__GXX_ABI_VERSION;1012;__SCHAR_MAX__;0x7f;__SHRT_MAX__;0x7fff;__INT_MAX__;0x7fffffff;__LONG_MAX__;0x7fffffffL;__LONG_LONG_MAX__;0x7fffffffffffffffLL;__WCHAR_MAX__;0xffff;__WCHAR_MIN__;0;__WINT_MAX__;0xffff;__WINT_MIN__;0;__PTRDIFF_MAX__;0x7fffffffffffffffLL;__SIZE_MAX__;0xffffffffffffffffULL;__SCHAR_WIDTH__;8;__SHRT_WIDTH__;16;__INT_WIDTH__;32;__LONG_WIDTH__;32;__LONG_LONG_WIDTH__;64;__WCHAR_WIDTH__;16;__WINT_WIDTH__;16;__PTRDIFF_WIDTH__;64;__SIZE_WIDTH__;64;__INTMAX_MAX__;0x7fffffffffffffffLL;__INTMAX_C(c);c ## LL;__UINTMAX_MAX__;0xffffffffffffffffULL;__UINTMAX_C(c);c ## ULL;__INTMAX_WIDTH__;64;__SIG_ATOMIC_MAX__;0x7fffffff;__SIG_ATOMIC_MIN__;(-__SIG_ATOMIC_MAX__ - 1);__SIG_ATOMIC_WIDTH__;32;__INT8_MAX__;0x7f;__INT16_MAX__;0x7fff;__INT32_MAX__;0x7fffffff;__INT64_MAX__;0x7fffffffffffffffLL;__UINT8_MAX__;0xff;__UINT16_MAX__;0xffff;__UINT32_MAX__;0xffffffffU;__UINT64_MAX__;0xffffffffffffffffULL;__INT_LEAST8_MAX__;0x7f;__INT8_C(c);c;__INT_LEAST8_WIDTH__;8;__INT_LEAST16_MAX__;0x7fff;__INT16_C(c);c;__INT_LEAST16_WIDTH__;16;__INT_LEAST32_MAX__;0x7fffffff;__INT32_C(c);c;__INT_LEAST32_WIDTH__;32;__INT_LEAST64_MAX__;0x7fffffffffffffffLL;__INT64_C(c);c ## LL;__INT_LEAST64_WIDTH__;64;__UINT_LEAST8_MAX__;0xff;__UINT8_C(c);c;__UINT_LEAST16_MAX__;0xffff;__UINT16_C(c);c;__UINT_LEAST32_MAX__;0xffffffffU;__UINT32_C(c);c ## U;__UINT_LEAST64_MAX__;0xffffffffffffffffULL;__UINT64_C(c);c ## ULL;__INT_FAST8_MAX__;0x7f;__INT_FAST8_WIDTH__;8;__INT_FAST16_MAX__;0x7fff;__INT_FAST16_WIDTH__;16;__INT_FAST32_MAX__;0x7fffffff;__INT_FAST32_WIDTH__;32;__INT_FAST64_MAX__;0x7fffffffffffffffLL;__INT_FAST64_WIDTH__;64;__UINT_FAST8_MAX__;0xff;__UINT_FAST16_MAX__;0xffff;__UINT_FAST32_MAX__;0xffffffffU;__UINT_FAST64_MAX__;0xffffffffffffffffULL;__INTPTR_MAX__;0x7fffffffffffffffLL;__INTPTR_WIDTH__;64;__UINTPTR_MAX__;0xffffffffffffffffULL;__GCC_IEC_559;2;__GCC_IEC_559_COMPLEX;2;__FLT_EVAL_METHOD__;0;__FLT_EVAL_METHOD_TS_18661_3__;0;__DEC_EVAL_METHOD__;2;__FLT_RADIX__;2;__FLT_MANT_DIG__;24;__FLT_DIG__;6;__FLT_MIN_EXP__;(-125);__FLT_MIN_10_EXP__;(-37);__FLT_MAX_EXP__;128;__FLT_MAX_10_EXP__;38;__FLT_DECIMAL_DIG__;9;__FLT_MAX__;3.40282346638528859811704183484516925e+38F;__FLT_MIN__;1.17549435082228750796873653722224568e-38F;__FLT_EPSILON__;1.19209289550781250000000000000000000e-7F;__FLT_DENORM_MIN__;1.40129846432481707092372958328991613e-45F;__FLT_HAS_DENORM__;1;__FLT_HAS_INFINITY__;1;__FLT_HAS_QUIET_NAN__;1;__DBL_MANT_DIG__;53;__DBL_DIG__;15;__DBL_MIN_EXP__;(-1021);__DBL_MIN_10_EXP__;(-307);__DBL_MAX_EXP__;1024;__DBL_MAX_10_EXP__;308;__DBL_DECIMAL_DIG__;17;__DBL_MAX__;((double)1.79769313486231570814527423731704357e+308L);__DBL_MIN__;((double)2.22507385850720138309023271733240406e-308L);__DBL_EPSILON__;((double)2.22044604925031308084726333618164062e-16L);__DBL_DENORM_MIN__;((double)4.94065645841246544176568792868221372e-324L);__DBL_HAS_DENORM__;1;__DBL_HAS_INFINITY__;1;__DBL_HAS_QUIET_NAN__;1;__LDBL_MANT_DIG__;64;__LDBL_DIG__;18;__LDBL_MIN_EXP__;(-16381);__LDBL_MIN_10_EXP__;(-4931);__LDBL_MAX_EXP__;16384;__LDBL_MAX_10_EXP__;4932;__DECIMAL_DIG__;21;__LDBL_DECIMAL_DIG__;21;__LDBL_MAX__;1.18973149535723176502126385303097021e+4932L;__LDBL_MIN__;3.36210314311209350626267781732175260e-4932L;__LDBL_EPSILON__;1.08420217248550443400745280086994171e-19L;__LDBL_DENORM_MIN__;3.64519953188247460252840593361941982e-4951L;__LDBL_HAS_DENORM__;1;__LDBL_HAS_INFINITY__;1;__LDBL_HAS_QUIET_NAN__;1;__FLT32_MANT_DIG__;24;__FLT32_DIG__;6;__FLT32_MIN_EXP__;(-125);__FLT32_MIN_10_EXP__;(-37);__FLT32_MAX_EXP__;128;__FLT32_MAX_10_EXP__;38;__FLT32_DECIMAL_DIG__;9;__FLT32_MAX__;3.40282346638528859811704183484516925e+38F32;__FLT32_MIN__;1.17549435082228750796873653722224568e-38F32;__FLT32_EPSILON__;1.19209289550781250000000000000000000e-7F32;__FLT32_DENORM_MIN__;1.40129846432481707092372958328991613e-45F32;__FLT32_HAS_DENORM__;1;__FLT32_HAS_INFINITY__;1;__FLT32_HAS_QUIET_NAN__;1;__FLT64_MANT_DIG__;53;__FLT64_DIG__;15;__FLT64_MIN_EXP__;(-1021);__FLT64_MIN_10_EXP__;(-307);__FLT64_MAX_EXP__;1024;__FLT64_MAX_10_EXP__;308;__FLT64_DECIMAL_DIG__;17;__FLT64_MAX__;1.79769313486231570814527423731704357e+308F64;__FLT64_MIN__;2.22507385850720138309023271733240406e-308F64;__FLT64_EPSILON__;2.22044604925031308084726333618164062e-16F64;__FLT64_DENORM_MIN__;4.94065645841246544176568792868221372e-324F64;__FLT64_HAS_DENORM__;1;__FLT64_HAS_INFINITY__;1;__FLT64_HAS_QUIET_NAN__;1;__FLT128_MANT_DIG__;113;__FLT128_DIG__;33;__FLT128_MIN_EXP__;(-16381);__FLT128_MIN_10_EXP__;(-4931);__FLT128_MAX_EXP__;16384;__FLT128_MAX_10_EXP__;4932;__FLT128_DECIMAL_DIG__;36;__FLT128_MAX__;1.18973149535723176508575932662800702e+4932F128;__FLT128_MIN__;3.36210314311209350626267781732175260e-4932F128;__FLT128_EPSILON__;1.92592994438723585305597794258492732e-34F128;__FLT128_DENORM_MIN__;6.47517511943802511092443895822764655e-4966F128;__FLT128_HAS_DENORM__;1;__FLT128_HAS_INFINITY__;1;__FLT128_HAS_QUIET_NAN__;1;__FLT32X_MANT_DIG__;53;__FLT32X_DIG__;15;__FLT32X_MIN_EXP__;(-1021);__FLT32X_MIN_10_EXP__;(-307);__FLT32X_MAX_EXP__;1024;__FLT32X_MAX_10_EXP__;308;__FLT32X_DECIMAL_DIG__;17;__FLT32X_MAX__;1.79769313486231570814527423731704357e+308F32x;__FLT32X_MIN__;2.22507385850720138309023271733240406e-308F32x;__FLT32X_EPSILON__;2.22044604925031308084726333618164062e-16F32x;__FLT32X_DENORM_MIN__;4.94065645841246544176568792868221372e-324F32x;__FLT32X_HAS_DENORM__;1;__FLT32X_HAS_INFINITY__;1;__FLT32X_HAS_QUIET_NAN__;1;__FLT64X_MANT_DIG__;64;__FLT64X_DIG__;18;__FLT64X_MIN_EXP__;(-16381);__FLT64X_MIN_10_EXP__;(-4931);__FLT64X_MAX_EXP__;16384;__FLT64X_MAX_10_EXP__;4932;__FLT64X_DECIMAL_DIG__;21;__FLT64X_MAX__;1.18973149535723176502126385303097021e+4932F64x;__FLT64X_MIN__;3.36210314311209350626267781732175260e-4932F64x;__FLT64X_EPSILON__;1.08420217248550443400745280086994171e-19F64x;__FLT64X_DENORM_MIN__;3.64519953188247460252840593361941982e-4951F64x;__FLT64X_HAS_DENORM__;1;__FLT64X_HAS_INFINITY__;1;__FLT64X_HAS_QUIET_NAN__;1;__DEC32_MANT_DIG__;7;__DEC32_MIN_EXP__;(-94);__DEC32_MAX_EXP__;97;__DEC32_MIN__;1E-95DF;__DEC32_MAX__;9.999999E96DF;__DEC32_EPSILON__;1E-6DF;__DEC32_SUBNORMAL_MIN__;0.000001E-95DF;__DEC64_MANT_DIG__;16;__DEC64_MIN_EXP__;(-382);__DEC64_MAX_EXP__;385;__DEC64_MIN__;1E-383DD;__DEC64_MAX__;9.999999999999999E384DD;__DEC64_EPSILON__;1E-15DD;__DEC64_SUBNORMAL_MIN__;0.000000000000001E-383DD;__DEC128_MANT_DIG__;34;__DEC128_MIN_EXP__;(-6142);__DEC128_MAX_EXP__;6145;__DEC128_MIN__;1E-6143DL;__DEC128_MAX__;9.999999999999999999999999999999999E6144DL;__DEC128_EPSILON__;1E-33DL;__DEC128_SUBNORMAL_MIN__;0.000000000000000000000000000000001E-6143DL;__REGISTER_PREFIX__; ;__USER_LABEL_PREFIX__; ;__GNUC_STDC_INLINE__;1;__NO_INLINE__;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16;1;__GCC_ATOMIC_BOOL_LOCK_FREE;2;__GCC_ATOMIC_CHAR_LOCK_FREE;2;__GCC_ATOMIC_CHAR16_T_LOCK_FREE;2;__GCC_ATOMIC_CHAR32_T_LOCK_FREE;2;__GCC_ATOMIC_WCHAR_T_LOCK_FREE;2;__GCC_ATOMIC_SHORT_LOCK_FREE;2;__GCC_ATOMIC_INT_LOCK_FREE;2;__GCC_ATOMIC_LONG_LOCK_FREE;2;__GCC_ATOMIC_LLONG_LOCK_FREE;2;__GCC_ATOMIC_TEST_AND_SET_TRUEVAL;1;__GCC_ATOMIC_POINTER_LOCK_FREE;2;__PRAGMA_REDEFINE_EXTNAME;1;__SIZEOF_INT128__;16;__SIZEOF_WCHAR_T__;2;__SIZEOF_WINT_T__;2;__SIZEOF_PTRDIFF_T__;8;__amd64;1;__amd64__;1;__x86_64;1;__x86_64__;1;__SIZEOF_FLOAT80__;16;__SIZEOF_FLOAT128__;16;__ATOMIC_HLE_ACQUIRE;65536;__ATOMIC_HLE_RELEASE;131072;__GCC_ASM_FLAG_OUTPUTS__;1;__nocona;1;__nocona__;1;__tune_core2__;1;__code_model_medium__;1;__MMX__;1;__SSE__;1;__SSE2__;1;__SSE3__;1;__FXSR__;1;__SSE_MATH__;1;__SSE2_MATH__;1;__SEG_FS;1;__SEG_GS;1;__SEH__;1;__stdcall;__attribute__((__stdcall__));__fastcall;__attribute__((__fastcall__));__thiscall;__attribute__((__thiscall__));__cdecl;__attribute__((__cdecl__));_stdcall;__attribute__((__stdcall__));_fastcall;__attribute__((__fastcall__));_thiscall;__attribute__((__thiscall__));_cdecl;__attribute__((__cdecl__));__GXX_MERGED_TYPEINFO_NAMES;0;__GXX_TYPEINFO_EQUALITY_INLINE;0;__MSVCRT__;1;__MINGW32__;1;_WIN32;1;__WIN32;1;__WIN32__;1;WIN32;1;__WINNT;1;__WINNT__;1;WINNT;1;_INTEGRAL_MAX_BITS;64;__MINGW64__;1;__WIN64;1;__WIN64__;1;WIN64;1;_WIN64;1;__declspec(x);__attribute__((x));__DECIMAL_BID_FORMAT__;1;_REENTRANT;1 +//C compiler system include directories +CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS:INTERNAL=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +//Name of generator. +CMAKE_GENERATOR:INTERNAL=MinGW Makefiles +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=D:/2021_2/cids-server +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_COMPILER +CMAKE_RC_COMPILER-ADVANCED:INTERNAL=1 +CMAKE_RC_COMPILER_WORKS:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS +CMAKE_RC_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_DEBUG +CMAKE_RC_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_MINSIZEREL +CMAKE_RC_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_RELEASE +CMAKE_RC_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_RELWITHDEBINFO +CMAKE_RC_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_READELF +CMAKE_READELF-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/share/cmake-3.19 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 + diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeCCompiler.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCCompiler.cmake new file mode 100644 index 0000000..67f5999 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCCompiler.cmake @@ -0,0 +1,77 @@ +set(CMAKE_C_COMPILER "C:/BC/C/mingw64/bin/gcc.exe") +set(CMAKE_C_COMPILER_ARG1 "") +set(CMAKE_C_COMPILER_ID "GNU") +set(CMAKE_C_COMPILER_VERSION "8.1.0") +set(CMAKE_C_COMPILER_VERSION_INTERNAL "") +set(CMAKE_C_COMPILER_WRAPPER "") +set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "11") +set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert") +set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes") +set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros") +set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert") + +set(CMAKE_C_PLATFORM_ID "MinGW") +set(CMAKE_C_SIMULATE_ID "") +set(CMAKE_C_COMPILER_FRONTEND_VARIANT "") +set(CMAKE_C_SIMULATE_VERSION "") + + + + +set(CMAKE_AR "C:/BC/C/mingw64/bin/ar.exe") +set(CMAKE_C_COMPILER_AR "C:/BC/C/mingw64/bin/gcc-ar.exe") +set(CMAKE_RANLIB "C:/BC/C/mingw64/bin/ranlib.exe") +set(CMAKE_C_COMPILER_RANLIB "C:/BC/C/mingw64/bin/gcc-ranlib.exe") +set(CMAKE_LINKER "C:/BC/C/mingw64/bin/ld.exe") +set(CMAKE_MT "") +set(CMAKE_COMPILER_IS_GNUCC 1) +set(CMAKE_C_COMPILER_LOADED 1) +set(CMAKE_C_COMPILER_WORKS TRUE) +set(CMAKE_C_ABI_COMPILED TRUE) +set(CMAKE_COMPILER_IS_MINGW 1) +set(CMAKE_COMPILER_IS_CYGWIN ) +if(CMAKE_COMPILER_IS_CYGWIN) + set(CYGWIN 1) + set(UNIX 1) +endif() + +set(CMAKE_C_COMPILER_ENV_VAR "CC") + +if(CMAKE_COMPILER_IS_MINGW) + set(MINGW 1) +endif() +set(CMAKE_C_COMPILER_ID_RUN 1) +set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) +set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) +set(CMAKE_C_LINKER_PREFERENCE 10) + +# Save compiler ABI information. +set(CMAKE_C_SIZEOF_DATA_PTR "8") +set(CMAKE_C_COMPILER_ABI "") +set(CMAKE_C_LIBRARY_ARCHITECTURE "") + +if(CMAKE_C_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_C_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}") +endif() + +if(CMAKE_C_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "") +endif() + +set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "") +if(CMAKE_C_CL_SHOWINCLUDES_PREFIX) + set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}") +endif() + + + + + +set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include") +set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "mingw32;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc;moldname;mingwex") +set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib") +set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeCXXCompiler.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCXXCompiler.cmake new file mode 100644 index 0000000..1766f01 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCXXCompiler.cmake @@ -0,0 +1,89 @@ +set(CMAKE_CXX_COMPILER "C:/BC/C/mingw64/bin/g++.exe") +set(CMAKE_CXX_COMPILER_ARG1 "") +set(CMAKE_CXX_COMPILER_ID "GNU") +set(CMAKE_CXX_COMPILER_VERSION "8.1.0") +set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "") +set(CMAKE_CXX_COMPILER_WRAPPER "") +set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "14") +set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20") +set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters") +set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates") +set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates") +set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17") +set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20") + +set(CMAKE_CXX_PLATFORM_ID "MinGW") +set(CMAKE_CXX_SIMULATE_ID "") +set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "") +set(CMAKE_CXX_SIMULATE_VERSION "") + + + + +set(CMAKE_AR "C:/BC/C/mingw64/bin/ar.exe") +set(CMAKE_CXX_COMPILER_AR "C:/BC/C/mingw64/bin/gcc-ar.exe") +set(CMAKE_RANLIB "C:/BC/C/mingw64/bin/ranlib.exe") +set(CMAKE_CXX_COMPILER_RANLIB "C:/BC/C/mingw64/bin/gcc-ranlib.exe") +set(CMAKE_LINKER "C:/BC/C/mingw64/bin/ld.exe") +set(CMAKE_MT "") +set(CMAKE_COMPILER_IS_GNUCXX 1) +set(CMAKE_CXX_COMPILER_LOADED 1) +set(CMAKE_CXX_COMPILER_WORKS TRUE) +set(CMAKE_CXX_ABI_COMPILED TRUE) +set(CMAKE_COMPILER_IS_MINGW 1) +set(CMAKE_COMPILER_IS_CYGWIN ) +if(CMAKE_COMPILER_IS_CYGWIN) + set(CYGWIN 1) + set(UNIX 1) +endif() + +set(CMAKE_CXX_COMPILER_ENV_VAR "CXX") + +if(CMAKE_COMPILER_IS_MINGW) + set(MINGW 1) +endif() +set(CMAKE_CXX_COMPILER_ID_RUN 1) +set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;CPP) +set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) + +foreach (lang C OBJC OBJCXX) + if (CMAKE_${lang}_COMPILER_ID_RUN) + foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS) + list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension}) + endforeach() + endif() +endforeach() + +set(CMAKE_CXX_LINKER_PREFERENCE 30) +set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1) + +# Save compiler ABI information. +set(CMAKE_CXX_SIZEOF_DATA_PTR "8") +set(CMAKE_CXX_COMPILER_ABI "") +set(CMAKE_CXX_LIBRARY_ARCHITECTURE "") + +if(CMAKE_CXX_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_CXX_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}") +endif() + +if(CMAKE_CXX_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "") +endif() + +set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "") +if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX) + set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}") +endif() + + + + + +set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include") +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;mingw32;gcc_s;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc_s;gcc;moldname;mingwex") +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib") +set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_C.bin b/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_C.bin new file mode 100644 index 0000000000000000000000000000000000000000..89ba4ac02c34b74655edbabe34ea104cb5325d86 GIT binary patch literal 53904 zcmeIb4SZY0l{Y-HEk{o5NC|OpASr@6;Lyae6DK4gp;jz85|M4;j}RdAT9)OHMwW#> z5{IU(!EuXLc!hrY-F%4W%h%)0C$8 z`Jb7&_v-4}4*1#K-}ZgEKV8ktnKS2{Idf*_%-pZ0o5xupW2^}0F+00u{0p6|kFg8{Im51E^9l;y!`=g=4LIjAc5)Fy2NkNPKM^kw za#PaEkf6h9;lMYCEWBO-aIh##QBFh)av%b4n6bbd5#|2@#$u9m4s_aRXFX$8Q{+B# z2V>(9ZMvg686HX^^Tnn3BN3_Y)F?SeCku2|cL$R}z)ldn1}DjO1ts*Oo&_eV;{x#v z(Wu8+j8j!QqIA@=&id+@z~gm9T{+LIdA9af&uZ$chXmdmREJKS#J3t}&cX4z5(xqg zm*6j!lbI78W}Oq&{em9X^)NDRIH^842k1>yH?+1B2&MrA;v~Lg6FEmctDmS&MmS#w z!4KjjyiGWB4#HbqCjbEo4&fxc&6Lm&=x^)l+Kn7wy9~huPAAUmaONEK%&~R#+FB0r zkzP*XBzhmfnR9Twx^*0K1?8W?N$t{!Gw0xV>#pGtFaHNo!tc&OLbRUMZ(V&&4F`UX z{v8sphl8{~qNgRMi5#_G=4Py?+J4yqj^Q17waS~ZhM}g~=Z-O|6_PzjYKi{b#LC=+ zeJx1cv7zba8@dF4FW}FcDgOfSGYiv>>@TgH%}3WT zHnPEzyt#J5JMvT&WMf|?39{9|KmASnW%bM(@^1E8j^D9?29DHy_Q$;yJ$L+Jo+Y`F zf`Zh?M-Ed(=G#AZ`{d+g=B{%{)IK-*P5Y;xJksM|1DF;|DHz2n9mZQeUxy_Z-|e6|$y_urr)coGevR7e#wZHaeVm5zf`A7_ETHxLIwEaLG@V=VG$nKha-kZ*z@!J1k zt#@=H^)qi~-Em$fQ#^9cVn09znJGqn58Q^>G3)7D8E;?euk8nF5uzT;P}G}Y zpp-22)J}X2P*(fR$rIT+jM32ThwYd~%6~UVSmpJEoG!=?&F6Wa{L|!Q_K6B8e-4xn zVkc1tZ`%4(m~Hk^z-zxLNT-&bR#baD@LY1`$WJZFtGFR}M&XL;2Zxn_1){o z+{@2-kAVb{T{Qyg*$0KTzqcBoOnDzbnX)*sh3eA|f5zIu6XiPyIgKuoDZ3WYv~?r? zVI~KTf>@^fy_9+`H81-Dm}RU>k@Vj26xrD=A5d;}?Q-3E)c&};vh$P`hA#96^LQ9s z|Czd-FoDsR(QaR*VKDnyBE!vQGz%a^`#hJh>|+SB{m32t^|4~I3H#{xfPfD6@xoKz zKn%p?_>z8hvV3HKu~X{_JPsQBQ21D}7-`CO5v9vO>C}gipFWcPT{(J;-kx%N`Vy7l zcAEVfN@oA*{N&^~bu1b*>doU>isM5tmi-IDADsz5`&saWiQDg)us=5O`xiOcadE)L zX=Xe1JRchB*-;5sgAQ-{7m%?g-Q@75J1Vj-0r{BcJaNu=9Nv2|TBI?(+8--&*uOqu z@tn_i&Vzo}Skh>6|RzxSML5r09G^UFoML%gYc+e`B(IIpqPZDt&CSyoM5Mla*EO z^hxj6AR!JwYR{x!^VU9{K8Kk1@)O>TFD93J(@%PT{~QL4yD(@&=bxk?hc_Q@ykC3f zR_Aj)FbD79wNmiY-`4fhfd=6g5%Z?M3k|=zlLpAIeGsHF%YFz|dB-|l#7OE*|I1|g zR|rf)@!z7#$T;asAMvGMBrR+pEuj1(DDO?TSJogq>rJEb7&Vc`q}}o2Wch8Ju=OJ# zOz?Go;^@{M3}@cMB}Ht4ceAwBLx7C+?<k%hwT&v9f|HlGKaDWcmN< zXY6ZK9HZA{c_m=k-3y6=rvmzM@M?Hqm)0+V->DBlr)qnXHIBSln7nxOx#UHMId|%$ z+IW!tb}1Ge8hl)}Uu)=U@&yW##mBe{H1cLa@}iM9Ey;Qf`IZmx_Fs12UXpj+rzqI? za`GqMOd-ur1?V>zXaP$7I=4*rrd*C70xQ?sE8jjLKlw60prI2)SH5m{9H<;dTafCx z@p0|HZeM^l!T+wx4fuCg)=!?G;b^Dm6*_%yx-1P^r`i|Llu^%keTVETl9l!L75gg# zZu<%h$Ritz?H_*@Tr%je#=3`g5Bv)sPo&{vWJmAwI6NF{jsrSB_Mk$qNksw{9StbK1%!bw4LxbBTY8)1)*XP@{ZL#<~{Pu zLa*hFKi%mR6Lr=NH_estSC(>D&2^Z&W0oUe{@l%^Wq(b@Wcj7NoTB}}FR3ZrmF}^? z`H`RfF=-pg){mV0->I$<>lc7+8JV;tR@9$8R%9O?2j=Kx(qVth!vHC`tI$6BS-{XN z0XgWU&yD=X;?1;M&!HTwukc*_rz8J%u66vND&YLd1DE`{%m*dT0chB0UKQV#`}SfWLKWC*V-PvwS!xdvZBxsJ#-7sk^2kd(_U! z-VLZX{iE!oNRFfDb+~SH?I0(ZeBhB+H+aV$sT_u=nPqo^%;=Ak3%q0D!>BoVE3OZ? zlv|G;vxbmGLq>M~JW#`&S~QIF8}9+gJ96?&_8K$}+~EMKaLl?1$aKK7X#v2y;wkSK zIpt|<6>|KT23DN$j+~qGkLJuS?mab3PQb?w13vPm(|+KiJW_8TJ&6dM3)f-t zeEsR)!=vz9z6FQpA%FVy>`pjWM3L)mA#rRj$`sol+kxJ9%5TYzya^Z9mU_@_f7}9m zly6Eu>AT}w#JvY~ZnAry^sSg^vK;qAX|BWMP-Y83^z_5ynFT=irBC=v-UO!4?mHn> zZIIxFKTb}bqE;IpdDE6!=e9p)WP}{g0TUl?QlF!u*8u^2;Ir>VHII270)Lh*fKdUq z9kA?K3>9LAqxmgk+44zj66_6a8AFix&=zO~leiW1>>vL&%5FgohV2L5ps1DdM#(>~ zeeSC;UzYvpTxtMXi&2a4`F}GaJah7dwiFiQ@s@iy?SDeSz1M8{6i?hwbpHy`)F5b5 zlVryv&Ez1>T01#VqqXJJz)kjV`3x1=j3Q*K*_$;n?n07_L0ovIR&;#JGAjG+Eq7CJ zr8ci(niKMoH_n6%B_Nnx`X*ln2*=#bE6oLb6<##2^yn?nbxx`8BcpcW)Eq!*ei1ob zz^{s&U&AK#`9b7!J>Dnszk__<`%WE2Oq(y9*-y>^%k(!g)<6gKxYTm*=&zGbG->v7 z8Yk8RO2TI!MiY_N7OAy!%7ItTcPn1=(tBq-Ra(!e0n<)Z#k1|Xw{f1 z<}#$d;T=7jejRIbt`6uA;yw(HzH}Djb|)s%8%ce{^7Jbt9}S`y;umBJFfFE!-0@Rn zJMZ{IL&G-oU+Uq)RQrUf?w6)|2pRT|bNdvg`US!yQ%zl_n&~FAn=sQGpeC}9Q9DI4 z)^lwleSr3%Fq2}ga^B*dJW2B8+UrhkugOMXt52)8`crBbZvQ_4SJM1fq`e-7@U$Lr z-lEyp*{wwwx@co2CsP>oYuupiqaQ@3YSg0|?SB-s?FVS1M;bLJar$qBO+UkJ+CKU| z3AwSF*&LX@DXAmR6a!I8Y?@5@`LR9Yy#;P`MRLxYt2c%x@~c zjP>t;QhRoEBK;lMcxoQDI3)hjuT?{ZL zR+i-OWlcP2fK&2OWarTQI&?94`me{ieP^tzfCtv!PTBeR$PHu|T#3{Q!9 z^}Mjnl2*!ZL53b>h=P*L4)rd~slv%s1xF9l1T+yNp75;tHWA8=%E zp;2M1>=};vGY~)hJRc7*JJXgMBWm@nn&6=N$G}PnVqn82Y0^ zKOWD14nx|hB$O}byO0a}uSaSp?$}5>uu03&+KHY!_EpR)z-|e7?ssg&_HPN6QG(y; z?~<1E@!BiO+aGr=f*WS3us`lAMwM2KoWe?{H0>YrAFpy}>PvkaPx#YE_S$Ha-1zKX z+QO^yZ#YPvaft2g~@)`JQ_^*4A! z*F*eg1^ZpZ-i5u-e!rvl)0Q+-RV(+4@aBuossT)z1?2~A8u-fhm)o+GK{uM`jmI;^r@jx;D z>KBbZ=Noggisbu7eg#b|`V=&AqN-<{bm8B41p6*=TOqc8Ha;8A)dlrAgFc8qsy})u zW7t*T8c5D_rzbcf$p>X@5R#nohPG~o59W3hs|fHvh5R0r*X3^|`3pp;Mjv+I{gxy7 zEm$pE5NqP&ReF1$t-s2NF$SxDyO(N)X7r*Nv(l~M{2=cSE>WB7JtX00V05Ds`%Q(yV} z6GyU_NuF+0#c(~vpIP?rOSnF-ZMxZ&{$^^YALjJG;LySz{Ju~F^!Z|DoG<;JOJ0j> z8t5B-8;rA_jPq*EINe9kH*SDEJlB*y5ifBUx@`W9PsSn85oq;D>St0re#?(i^H0A{ zJI{mV)AoxRmhGUmy;?Txe}N8NVUm-9pzNX=|e*zQlXSDV`cB zVcu0d#&h@nn|H+#FMvC5GOW(W$0wJc-ATUj!z*PtUxshpDEZ3p1sOgq!v|&f86K+b%g5{Vx3ict7(AD;MLzG5pA})J z1$x1(LhG>=&5UXO2TdFww=O0SR~qs+RzO{uY0{I+uQTwQTwW~YI14wD>q&+$$na?y zJ|@ElW%wBxeoTgYWY{Ca9Wrc`;d&WfDZ|AwESBL}cnF-o3}2Ap(=vQah7a;k)t9?H-L_VE9*g9KLnKaa^F4Pi3YGnGaM%_pjXm! zZUI9A8MIc<>nqk-E#0P!6ay@ zCHM9x`(6T0X>pr`A1|2&cLSp}fdoC`i2NMzZ8!XfWbL8zu;_yt`T*uVyOO z)t^K=-X6}ySLIUgcT&@VntC59B`O@6w@NWUhJ|B1_u`NK<$>65a5GkG}j%Gbw?_~-KQ z-^fd!$xCl*XxQYe8rra4Szos*Hkjxif~oeciih{qtaNTo^`qZ)?Q_EFx81nvMp!*; z=z}o770wOSwbis~_wHfT0DOH5PS%Or$PiwRtA|C1*C5=7vlQ`RgbyxaY!Tvz5I%>q z3URt8vjAS57jXx|6*&74uR*vOXAJRrgf5&(!~+Qb0_PCo;|RZj^8n%}5UyX$*xiJW zP{DaG;++V4ao&%33}FK2LBxjCR9fbGbEJFMs!Uu5L5I=UU|UR?=!5wAh`|KN-veh6V;Ip`ry;ni0% zb{F9wY{ofGaD-hr??F6<@KK!iB0hnz=_=@oa1cI)^C84fAe>(X+K4+4eiY|n#D@_+ zj&lO>34}LbmOGAkC&J>ZQ4VqTKE^J?`6A*@gjG0CB3^^=TAZ&SUXO4)&Me{qgty>) zm2g%vb|21C#1A6;63#P-zkB@m(trixSc)vHXsZmn5ZZ0bZn=orYUXqn$E<;(iGmX) z66XwTgUURLzW)qPvTF+S^Irk%yv(Oi<3arBv=v%ytwn{FKu%t9AuHZmP-E$oI4bVk zVm7z6xW?L96e|oAOjzbxt#h9%E-b7m=$x@U$^1o0YjFu%d{;4Z3|ZN{z9Lrqvnlux z|1Jq9o}bF$SuuCCqR`P*S~IV6ZmeWt&I#+u!ZVhDRxiR|lY?(9VAeI38jH=!Y+H+J z3Ofs8T-N-wil>HZohh7C#OAEwwTx+ea@$I6v#G+V=t!yXy#m*Kb!|4xQq zm*Gn?d_{)mWLP{Z=wBhjIvJ{UaLe>A8AfC{B*Tx%@G~-eNQO_y@M#%7FT^X={=2kCnZ+HBgp=V0 ztV*$>jI_x$RjtK?6<|Cc%qj}Dg_8}bcpM8vESo}Dm$4;gn6H~H%YnA{#lyjF09hA7 z{lP@iLyKhiX_RhDVuhQE`Jz38E_Rwj_9c?xfp)9~U5Up2NSI=5P9bpH`$M}M2C+_r zA5iFvLh4`y>!^G|4;T8w!96B0Yb@f6!~j;@gYf}cL33i^IJ>{7H5tKDvoRIr%gXj( zS0v0nPtb;7EQ#f4!yr_GCtw~Rn166^cPgeLLs{{CjD3Z2f^hr_NXR|2iwC&YzO#yTErf@U8~_TWA2wa#p}4vGIS$)%84F!~e~H z*y;d&HU0&@8RK2ZpOXf#oLAeQmgP)s|EZ__?SjkK zyLUrv%`UlJjA-tbaZ=f{o^KrQ;{11M#8iA-HCe@JtX;E9(1)W1by@q#Jw- zY;z)m(Oz6X!e1&%P7tn-z;Qy3RnH+nQ40UK#HJ*fW&6s7C|tCc2vNGLLLp)Wa}s^< z$MOgjS*dtoiZF@)_n;K#T3CDe$F+CwV$2Nxe3dBmNUf4oZ68jPgu3ts^ z6Hvt?S1v)G07e021^=^>1fHuBhJPGl1xqZPW-fFOD_CZ^Xg^9@ZFlm2;-q2hMM0ok zZdv>Vp7|yI|5rIEaJKv7xR6zFl^~-Q-K%A+6ou7{SnmKDi50A|EF^|1c&`e-#!^mP zRQO;b76~S4!NUqRTb5i|NRoabM}WZuE?=<%m&j9#Vg16vjVACw@Pn}Sg6-yv{wQSx zL`E?@{;tSwT<2ni>nE0oLT*!S@9RHSV72=)uObS12?26EZ{ zfR=s@5eF;$IfA(uEU>bbvL={qr{xmLmhe4##@~yK1!}D*2TShWeXO+PUmd%P8CysL zN6E|f{m?C2NGd7$$ud$#(Zc8;wi^*)EBTS_5u%e4*UJ^U z%F9Y#x|C?Jg(CG+>k~jJVm9JPQ9dLUvO+3(5#|%xR~d|>izJc>c9*5(m$rYMN8)sM zvyy)+6S76ZK~|FGiK2yxzWyFe78vqNPH~V;f-t>dbSwE42bL}zz*T>-fG;^+_Bv=f z1PIroS;?H1vi+GXc%K z&MCMFC9FWR{e!IJcO2&B#kwMB(;zDG?;Pk~2osf%vt@HiaeanE5|~WE{|_9rYhh1J zA%d*rkGxbL0R)-z93w&iS>`Pc8Co<0OF-ZYSTr7kTFv_44f)s0b|*VkHg%KVL54 zv2a`oM_>RB%TjJzmhuGdZ@}Q86^i$%^Nu<0jL4MxL*sRSQu2rZmoB^L{n3QKtx?w3JP z>LjdWi2yIPl=tvna*0Sgkp>}Fa;ZpHA`SCqB}+xRitxKYc9}@8L^{-m^m|0Q2I<6Y z*nTRxOaSU28kzv3RLKY<0V)NcUI1YB%LTvB>({d0LBUdXonyWj8Lu?kew0&oc9UHE=xH!UNMw}$Y5B>N&)WF z!9A$QO3NkGfZaM2!>?N4O3LapW{E=AP)-C@6WePgYb{GIN2iK$2zCY;AXgA%$Wo3` zs9Q+}cZZ{jq1EbyK*JIP?_!z?YrViafY&7*!2oF^#x!>EQL~5@{tR&rq!EMz3s~Xr zRUq|r4n*-%#I3d%h|KLLk6YNzCd-wZcm@r!B7??hnR~5eIl&k60C(zpBZ`s!2Q99Zv8@2VYQa#%f@R_p9^lYlC z-{V4=`8qJr(dJc}xSE(<2NQiiS_`?%p@ZEm9a~lK0v)Vkw*=Ti9jYP&dXWwdxZFyc zx23gRY3yijX!o@=vqi?-R!@6JYjYbb*TIb~9j(gs9cU-NugTZW7VBBibo-62R><1w zY4o6xNi$nL&7MYI1I&?KtfTrH0@4C1bYQCo0yVX`eT_G(D6wfZ7y#kd#@4J;BR-cN+WD*J6oZcB zqinrN3G8fXWoz_IGUZkXjd7MNpiOCSQFg%E*Uo^_*xJ&>k?N*IqIUAMwxLV6v2{9z z7|ac(+8E%C>S=|d*Xx+nrjP*@QF1Y^nG!>A1Az^CHt$Y>Hg8AcR<=7o4s?*y7kjF`<59HjV*tj z0Tb-BmVUn>hnT6>Qm^O8QT9e(yO%~6=F+oV{u^C4wJD95)i4L5ehN&SZPgJ(kE71- z_cXHxJ)_O*YizG&ZXI&7hlYlo?U>dT!K>NLJbFGxj;0ocVuyuGe!^7lE7*G1+g= z$&@nQz{dvWH|KbL!s%$zvt)%xeXLmr3#0b8$Z5EZwdi?dPCFaC+qSZR5r`Vqup4w3 z)kD}jjbp4;&k?pK`vN8*%5KxMrKbXgx_x{Oh2Ck#efHFQTHfUa<(p5;gLv7OBJ6#UY^fG5bk%^RgB$vwuNaFFgGfUo`q%VKgCg*QoC z(D~lv6$Qn$xM7r2ceTRdqKV6x4v_k!>nKq;Xv0?Q!;pb+;7+o4;UDt!*0vj60qG8M z02dp#ev#NNu$1n!aDcgJy4WiV7L!zShd^Chv|%B{O0F$fOav}gx^a7if{Xu364&At zJQxsG1pYuz824GQlA8+3{s(ASZF}**I3Dg*LfF~S+~}*V#Sh^QS9^1durg+c-$K=N zQ&3=UprFvcm4YIBn~y@P-Oa;dJLVJs+Tfcu_*=Ga^`Pwqz-GTeL`p!pS&@mk_I7`p zvaO|ks|)7HOU|?V;FRwaiBh}Yv(1HpfoGN3b0;}Ch!}s{TLP2`w-AXo*dV$-r5$!W zwc(QP`2su5eT}|W^l!>sC~CKp&y$?=MI3`i7uh{Kz@JL+bh&-2pxFkG4z9eObFsat zNeWt_%Ayrpk|U4?yhKW+0WOsQbPU05DXQPDvsjjsuN8Way~)+KUEyMK5ib(}9(UT& zP3v?DmvfnU))jU*ro={RfYG&KdU-D^{4%V7uiE|@tGFqn!DO2y(xC#Gh#d0HVKRz^8laM=7<6zPy{9-0;w=Rmfv$9hLc zz?_8{idE!*wr{{HCkLa+-RNqnt-&Hk2X1wPcP-X6d7w2|*W`iLVlk5ks>1>%2h`4K zU6v18!<;#wo5^vk#R5eyNW0Wmw(uJGo zx`ViDt)!%+oNxN`4UYb3Xpk-_ny}^yEE|o{gUj?Ds~|oXy_JvUqPLcnEF%nDgp}7B z`8B+vjvIWu>&^QRpD_yWBOHg7Za7QAu|s^08rQBa;!DnNtt>frG+ryCHT3j#Yqt7HOd>`Vt`V||Dh3FPT>_v64dFL&Q2?y{{ zE#l3oOfR z7tJfQU21b+9x13~^X6TLBrXG9$$S^#;>u!HXxlXJ+Ibu2QPOG$0!51Ja^UY@vKiJq zr<`4dz-F=dF2W-PtmJY~SWR1j64y#J1n#_Y%T-GRTB(&YD!UTm%rCMO+OC^NECf%Y zW3K|MrJ&=u94HGe0?NF3diKJy97#3+?IMn0)iD-H49=f0$_)VMVX=WP@QCll7lSZW ztfG!>BY6NXz_UhwuE$;oUcg%LZ?XJwei{BPa5(7^4NLCL7Kl%IzXkT5d-{7<_tPBC zLi>7gS-ZN8Kj488QoWa?@C|0U;)>pzYEs*Kduz7%uehSX0!DueCI#&C#44Y4!=}~h z%^R!9E5?l&)7`uw5ZBj9XEO5=Q7%q&?cTBkE+n$t&?*@OC8h9JSRqpt=S{vj4 zbMCLBn+jcR&NbC*YyK?N`DZ6|bq}5Zg49ho-7L3OoVpGlL@F=?W!%RYBMC_JLLPok zBvRy-YLE~T%&9>r^>t9DL$AegKpZphBJ7_7XBek0;lCqw=mPb+1kF8h0i1f^fO(EQ z*8>u`Kq>lc$-xWY+y|W43^??N7G9~saHB#FcY5*g$r(zKHogm-6BodF1vpeOpiSEg z-UQB>3(#>O{}AYq=7}Ue`~=9O971weN0e~1doO!NgAmS2;GEP-0S8+Y@g&{ph-TAD z;i+E@f}8gEb7T(qf;z8jL8k^d2&Sz?5SjHe;8e@6T#;PFz0k4(JhoF(JJc^+5rAr0 zXaT{zqgsAtioo1@EtPo~_&AmPVije83FuHaQQsd!P~ga~Us0U66k6KxkJnM;9s5u( z>hE;sk7Fw82ymP;;HV?*F5t+Kc3&^8a#mr)?ZS?1RE)V}phGuea?O*HrZ~PxdRB3m zs#Q^nB*Y6lxPJAbs#a-~5L(sq)R?N(8UTb=)f_!kwMx1aS|yzr4^^wAOQBVDB+~Iz zZQwCMsSV0|3iZ+t>XnoVs5PBJ8*1GJ4%K}VN{HT}Qu+_8yZoja(Ir6(EoMtm^)rNg zp&uGkjEAb92*5%=gkz{WFYr}>sJ{zd?>7=bO4Z?=hzpCtYL%3hH+jDZ0^>92Fjl>B z?S{JbdR~+kxUmE^&@4)`RUr@2`5sEn z;q=u%b9<4E85`ehtE5Tep|-^VfJIxFH)_*64XvE?8y^y8dbKXP`^bx3w$RHUlIdgQ!)nWw0ioE`25 z9bp?&;KppUKQ&ihUFm)EMc+c&NVmBH##( zP2rD8ZCs;igI`F*Eprh(RF%+F(u8IipFtbM`BvZ@RB<$Ih*G2tx^`kbW~YrQYAU_2 zB261p*qF2*r=|_+do&j4hdP_@(6k}mvWv&w@l2Se3^st8)+`maG1Z7f6!!z?kkp2- zgHHiMPiYd*LWb@}&mSkMGzgXY8{iD1nRH+4Fd$9?&M`o0KvGyZ)fD2&L-kJ10jGWj z9JO}~38{7HOY)T}86Liq*3l&7K9Ye9Q@^c#5@HIOryix2qn1LeBu_txkfw}B9YCd^ zgX#f??Ad&{fwKWP)7reWmI{qdm5GSjcibAC>8<4hz!CG;P;w|aweMGN7p*jvwY(EO z*Pw2sl__`mWM58b@?fV-eZ7`$ysRArggn#F7g6Ax#6+mu;Q>IrIPv4H$k<;YO6vk0 z@_B;b)FEF+^aQro1Rd4tbZzWKBh7vlP_Oc`98?WoYe{v4tk+uEspY8=wUudR6V^gK z08?Pjp<3@5a1hpOoKFZ<9XCF%X&x?8vM+aofm8fCF{F*DEP;?-Cgni{3Wy)x z4~ytYbaNf@CZaVMPW9Hg7(!(YI9CI5$bfS_AoNaQV_OJ$z{~PM)bJ|KQT=--mZ?c- z@v6nOP;HA&tu4qmG9GGM3~OycIL02X>iHA7dLDq4=UBIDV>P(59cWYP*<3GbedD37 z`s>xUAYyrkD$i#%c?jVH(6fHL6L~sOj0|}y+c3*xGI`Ao|6Y?P1~(>@s~#>`91;rs zIH%-ANOzO9a2=9=NXHidi5Vb&56FZ8a+FHpCOF+PPXcnn067PU1H-9~GY^(KY=B$} z$bO3N7kgD>{!glaGxjgJkFB)@ zQ#Bt$Ex6U`d$4LhW!3%Ey(_P&N9UmaQK&-J`7sh0Aazeb2L{Oc9?YN;BDwEWE#Vz; zr|(=ED6eyyxIb#*zRSeDb5`6pn7D5?aeu_bz176MZ&uvvOx){C+#fJ;Cm&L3Olm$h zEABNW?sVl|QWmyRcfX1IbtdjZv*Nze#J$qQ{T>r{TD=(SK0GV#RVMCBP2BG`alhKc z{jOPYuQYLAWa56n#Qh2r_wiYAcbd4Dnz-*baj!6Ozjs#Lmzua2nYbrS+-WBV1!;_u zHh*wd+$&7n&trI$l%>r_Ox%l2+#i}1_eCb|Z$}g#J$MGeV2**nOW8Sq>208Chq4k zq8s|fdbiG9?#0n7F@=vEq|G?>753VG#h2l$vrFZw7PZMg)cHc-(0T_SOv>~5P2TcU z*COS8DKq-va-B<8=1~#wBH@gOx=T}qdWm%|U#%FB)b$0mm#8~sZ!s>;0eKwcowDvz z?Rcmk2GC^YTz;HW3Jh?(2}q4fheO^2UMd7{UzT&O;6?QUa^Big)#0$rDV*wBze$Hv z=tt`CkT>TVRu57zyNq$R_(vC)eRLZ7TQK4rz5qB=2}zwjt*CHM9r9x$}K3 zvReI+tNuD&W(iq0gUp)sY7%Pu37V~{y9d{tH;w#H>DrJ!b{$&BIPyQCkNo)>dq>=9 zuirp<9gP46NZle6ce)2k;>daDqfndZ7v^?X`+Mxau1)KnQe~cMPLY0HJ7ngym>%aE zHxL94jZwzKRIhiW`DaX;r?+TJt;%+P6$}lK^>w=DWxEflT75^{kDItBP268GalgXE zeRx*fpE7Zen7F@W;!byQNo~lw-!&`l6DIE6ChpIhxSzwsVdOqOEAI5lV?&#++hyYZ zjEOrv4`Sqg@2t2VHgRt^aevCh{UsCkgR|oPsEIqxxdv_2Jz?Tb?*=#4{h?WLKV;(W zHgSK{#QpC~+z-u)`y(dqn@!vwF>xO^aX&mO?hl!`lQ(G8`~xQL`%T;@X2tyh6Ze%S z?)RIx_n5dJpB49mChnCc?)R9u`%TQ{Chkj3-0wDVuQPFfaaP>#HE~~L;(oxy zy~4!(gW8z+F;=bR+-DcvRofY?S6Zaw$_oRvYYpPeEty9j-iu>Ir?&npXMD_jZ zA|~!HnYf>u75BSL+}|*9?>2FN#>Aa16)Q9BB@tSg*P_w0cdk`y^LV2h?$OhLzL_)ix}2pMdc&)$1LN zHa4i;Ft)6FNtH(%Y5ni*8d*ta>z`-OAry{7*{ zt0VpWvnCJilb||zduW97ZQz_i-6?mfdpHT_N5JWZ#xU&yriP#G!V%YaOvQhL4q z#Bu8Jt{%dHHX=%pzC0_Qwh+8Zu!W$`<^r-95Y@L4kZM5G=ZOTwLl8}e>X&21bv>t) z=O*CLN9%ntaP9(xY6%?Nz)EjNpnP4=+kxXW=s5^TOnO8@KT$wvKU=3v z_p__}s{-fKfIMTU*Moo~xEq!N#rvMD;v{JevS< zX!RmG&48$PbO@ZA0NHHdz6X#Y1Fun{W6{$aGo%=SzF-X`8h`JIN+>?Mf zQHoLmayKBx@$h~?CJc2y1jr#nyMGrDb)_KaoC4%L26`c(`t|TWgPz|2PE4x>L}2q4 z(tmC(mI0!!zY6d&Me)V)od!DB$WjnV*1`+OBM?N_*e!tUGC<;hsQdFm=1%}(Y>U4E zBw(oN*8!;mM5p|1K;LCti8hD)tWV4}E37)G^@4*w?7Xv~Er37R(AWo$8Hr)(J zjiF6%p;AECxkmv}cWDHjzXU|RqeDPG2Z*@K!YO$@49JUyRz3=ddbgM;^<6;xhFbh9 z;XnYL`|E(*4|H8W1&eZLb09MZAkQ0cmH`scAl(0fJqLg*>aNh_PGcQZ_z!?F===*&VkcYIo^WFsS%h(IP2%KSqB^(As+@+)H@E9QN243F> zWE^q0_O<>odx_=G>#lSUk!*p7f|`lfIvWrqws6XuolA{ zcRg^98~RQMAQLF1OBe^F+ra$*AP&PA^%+1;80dT%kWzzf{1YHajSg?q5M%Y=rPuUZ zL>UmhO@9c;aZNwSV!r`ozea~31$c(z6$4};Aaw7X7;Ok=1t2wqD^JGO0rG&MR3jku z$S1849_$B@P9z0HeK*2M1LYKO4r_Jq*^4i-hG82Tgy?(}IBpQpd%+kWXx1FaLx4C9 zw)!|AG2rMje+Ljc^#1h=6XYx)4$fVzMIoMF88VEkO91IJK-L0s#-Qg0K-B#@c!T)J zE4?P{kfB~XsFWtNc#jxnMgvYCaE3ujuf-T3l+tVQF!3@#jsWr~kaUf`00=!7D%w<$ zFP*7JDV_3bz&W9{7iNb@IEofD$nz)SrOAvqD@E6KXr%~J3y8XBMbsJF21uPj9t9A+ z?u2s(AnNX%D0LqoCk>Pz0%Rv}h0X7g4o5(fum@lKAX;~65K0|JsY3`wO}~Xyb$7Tc z)vE;Y;l^Hk3`HjUqdkLaJlNG05ARV^k$!xnS7P5IHF0VUC^oap1(czZm)tlQrm z0M&soz8K*RM!O^UG$tM=SLic_Xn*lMVP!SGHi@^jSF7dvlaXYi8(;5M@NMJ}i1SC; zr$O5neH&Pb)Zm4%qzU9RqpwT{@g3E!AikiYBgRz*x-=IGbi~_eC>3l>vV&>HZ zpZIIuhA*kn*Sqi?5w~Y+2fmNTKk3ve^aRRNX-XYD;IrU`e4?R@O2TJf)Hge!MUwP( zEiA#>2t8$%PQhEL`tfO4PA)}Xam80Z^M%bv0x||CyhmCI@vp3#@Vn7Aw05Q%;6tO4 zNEbfKZYC>~I2h>;4~1gdL%L=>@f~sgT8t=6F|WR2lV>Vua0*;=WO`;h- zjX;X-M-RR|+|35|DG|ILe2*~3oR5WzrWIcd=eyRGIhpcH;?uzK8Bh9t#6TEdKvhs@ zdaaYvo9GGlNAO7|wyjNRz?X}{L&?@~XfWPQ0FSENDL?`7S#4fTX?Ij@s&$STnyM`K zCD278(61~ZEHWPKN1s=lE0OF-gyT(kHHZfvJXZ%fych$YR>BL*_!~o*(hXU=!`ipJ z;aM8fYCZAt5-uB`;1%rO4953W$Iv;eYhYzVZFo=>HiXK=!u0laC63Qt;MMIYj;E9iW?33@u%t`aR6!o;Koi>kG;WgDdgPOzbCam7oN_C+RQ=u+3wQE^;Af<@=9w{d7 zB2}jDT#_E1FDDf#yTkj0v8%ew$qyx%nyp0e4I{LnvKL=1;*CuN@U>u#fZD(W4+%w^ z@Z)GTjF~D?wTOZ*SZRY@?mIJ95m)M&J7`|S*y*F0Wh*8YO|Ab0qJ*c(yc-PuF0g7qJlou zh2Dez-QjpN9KmN`gHWWfN4g#_oC%CH;FbGv9YIA_SR`7LksbYTOoEY)C_V$y&Dz4r zj;I(Ny0t;Su|EPgQc6KRY>;L-t|486U`8$nuQVU!glnlx?Yt<8ZtbY8KbS~jbjRpQ zRo{p2oDH;N)O97mI!rNXb~JjyMb*7Z%wI_*mf)kaWR5nU%B$7fRk6cLUS}|bYGG*T z$3R2c;@`L)?4de@cGE050QZS9)F&p?T5I-WEJ3epieq4+A_Kt>4&rO^sjdXCjj{(X zG9u@Mw+eMATntimC3NWyN8qhDpwst5$J)3f^gMHKP-|@b#FA{;8&Y9>)C$eRx%O*Z z^+GweE}Jztkm!X+g_VL{PVCj>mEtoY-exYY)$j^Y<@q`U21S0G5{Weobo=?rMYfDK zx9ilVpEbEQIYE=BDx`(U$N{pw4_|lh_H|Ef0=m`cB?9q5e7HP;BJGg`z?cV8Vb%`E z0zE1jmf5Hh9=p&qCzYf$D2Z4&)Zfz|(nr3Ty0@7B(dYc|+fuPcd@PHc4No-58%Q;# zzHl&Rus$&&=zT=fnqjFyt;pA%LcD3%NTWc-l5llox6;;8YHP>x>go>%_e^1$qMc*Z zE1{w()S*f$5D8CR?P*Qd-XGd6CPo!mwI5S+>j=|Zi_o!N4`H>OB>LlE!q5>(Wz!8f zXq9l>)Ej47H|pYH<30$5^cxqjazK=hFWRRe7^9D%N^ctl62kjb;HLCO$v@}AguB1# zSeisArdkD`k#af8y*1-lrFN;_Fkdm_t-5fa&=I<)n(btFG!965WsQ3nXkXpLwApA+ zC=|g+3%6bc(& zqCE#bQ(>a&rcdpusxzz;scEMe#WdGpAhCz01M~;ocQ7nMbz{z5#p#;~f~&j&ls5}w z7}`j#M%Jc23>wrdyoQ z-8*^Rh*aXk2qc!)rk-tFXXo1COofQ3oF^%&?gXOx!U33Kz(I8(1)nn&>WxM(K;FwC zbTVzv7TGg7Yij$6Zjm#R_UF zMyaTfdP!N-FmDn?_oXf_#-o`{KF=rPdLVN^rx-B$xYX^$F064!QK&A*Bb~Z`=C)nV zHY&G0&P>zflN_~0mZ(3GA?uvd85*z@0= zNbXh!Xo;LR9Lk|o7_B-4^!cLbBlN{=G*?^hx=3$6&GR!3MQ9Q*;VMIqM&+knv69a^ zt-~(z%ykoOVdxG*bZS!LG^Do&?uny~QFVF5FY;^2nf!~H76?;$6Bl-pNPb<1sE literal 0 HcmV?d00001 diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_CXX.bin b/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_CXX.bin new file mode 100644 index 0000000000000000000000000000000000000000..f47a09a98beb146cf54b6e74d61d6a0a869c451e GIT binary patch literal 53913 zcmeHw4SZY0mG8*5967NgCB(sjq=?i32NK6loREZsTCwCvjcf~lBmqLNWm*1cWLxMX zaUg9CPAFR8uG^)Qw(KLXrIc>j-Ly+-=ai*IYYtz{(*$EBkYVN`<=c0PIps_vu~g? zTv<{wyIhhEco^%v+s<~4KGe>77)wKtv+Qa%Cok_k>^(qQk9#&_rxqY|P@!7-C*pZR zZc17i5_CB&99WaE@OlBj!J;fhIT0<$f(X1J#safMl>ZMf7L}y4pi@TMYZ8fSzwUtqU$Lol?a-P@lZ0%nytE#OW6nJk^9olgd-%8wB7su;}#|bo4 zgn!Yj%&h1TYagrZ74*2ShmdK*P4&sTKyR$FuDO*!FbyaWH}NH#$hvA-?O0_Z!udJ~ zeh4?=ZN!~*5#FjA0SHiV7&qZCWq+OIgkF}%aCRe00ZFw|82{BcILLb3}(1ZLu_QK7 zkeB@E@DZxWT>IU(PfSdt?>Ub|_45b6WB=q+r+WbLj+CTeYMBK7NiM^K37~I7raL{9 z;rO0|V^rWez|8ttkGhpYa{q|+2WV;UNa+uGP%@4n%~IA!dD8knDM-1?oxuMBYUWPc zGRZ}-V$^Lt>NW&c%+=;3?sLh{VHXMbT=6N?fV?R&>yeBgl*<7po(}k$-f!h!}Zas4=2C%ItF)GoQ+b)exjgUV|2{F1`DPiEKMTqS zu~VpnH)VYpW}A5&@apdf(#geV6xALNJfB!G{IVr+H8%wB@R-H^gk$I}=Z9Z)rB1kp z&sv7wTI#a9Pn>zBi?`H)=aci!T&CMIP(Lz97DL`y@aqLXcX}4uII-}YyL^}B2xMpW zgTKcAl=Tb-;PetJwBQ~ISsFsG_>R7k?@zs)dHxCD$XGvTneC zn8|@-AeJtDFQuMO&dIz8W@+nUB)xY&O?Gz62b5b~yIi*(vwz)P-hSE&Ll^pkd3*_6 z|DL*?FoAd-<{-SN5usj zr&{gQlu(10u!x@WrWbt#}63?9{O-)?l9X@08Zum{|x2W2OQ7fW& z%Lh*X=4~4LFd&`DOO3lnYAx>{-gK1tQ%@z&p81N-FKzwTo6ziIi9#`x9JjuRG&Sbw z+dyp8JF(0YK?|x^^_Wp(a`c17FqmCIwK}r;b3b4C>1z?&aLjug!zbx3ajExrKk}xQ zln@5gCG7VY>}SMZ?wlyyu$yX|py*sgU8$!hN=pz)eS4yG8RY@3B6WPCw2BgI66F={ z)G6;bAR#V5s?Vlg_f|iXI**w5%5m?8lZj>C)KlKyJ&yt79t_&h`Nt{9;?2h!?>C;k z)%koE%)xtPjTHRM_jLWVp+UGsM7^mWK*O)?qyh399|WoNk{?4=-jTMG7)iaUf1D`& zGJ$C*{yeITj8neUQD5pLX<rMGdy)(?X) z!PovfN4IuiIP)GUDqv&0o29HC0;H{fQ%2N0XA%875j{Uqx|V2+l;l;Aq+TQ@O2696 z*f*#+Mz4v|a=Aj_^rIeCBtu7615ugEg#_RzvR<s$bk%1zSOT_K9FZW>|><#(W_A|brflIl*}g_=$7^hFs>f6S8&!9U=5)Mxl-hK zJ+kBhusieT>ijmc&(_b3L z18?dCS~Xi=CkzPMcoFc1)`o7u&~wh4`kpuS5B}6~`^UOqNNBAlz+wKwV`Z3M9NrB- ziY@SC-1Ok~Tb@GNepd?09X@ISPQ`{_C;t)MFXMt;ppAX0r|k!t1))L^@{ZIz;XV3l zzSnZrpK5oCi8|wko90UU%Zs_I<~qXNG0RaffBt6DvcIZqqV)1^PSJkgRccCixqBpV zVfYt+NZ5umwZo_Wcd}#H`Vg=!!xOgn^4fF93+x9+fq8Hu;jlm9VSwb_lW#xxDZtPy z0XgWU&JX{a#hY%mo<})YU;g>n%ftV2zIqG;{1_$(e<|B=-kU1EB=-856W;u_F0gPN zsU;#1*ol(m>tPw*R3l1ncTAK(Oedr!vK`lC+1VCQ|un z_vQ;J_w^S}M}by-?(_-F5UB|`5S!ob0{rdMI{}9Rp5wzo$y3WnL#^d-Ox;ywnPYZN z_Fh1}sh?yXM{*QBug$f?wVj+`@_~n6Tkjottb7QfrkC6WG6#Q}nCBe{A3@E@TXB8B zrQCY#xHW_<8Zt6-=YSgK)Pf=0-+m83-r-YcGuNSU;0^~+h2z$ZK&A_xO%nj#^1T9He}`lWYHD3&4c@A?wGH17mZi8M&x)z3G6%m-@Xo?X|&| zA3g?~eWv32CEdW<|J>=Hp%K83mIgP1Kzh3k4&RdW_F`ZaL%*oU!S$3;UqDT~Qs7`9 zwI5ss6{0pbQ;PuE_rD=A_JF9W$wyJ|nD_J$IRSSc0etu^r~SZ3c%;^T@Dw6&E?h^* z^Yy2G2am#U`7RuuNByZcGCSd15k;=M`NXlYAYEvGVmo@@X}={i{1#kTTk;XN{p%Ls zqkKc^Dc_ynCGK6QbA#RclyCW1gXM%DN^>0{hcc57qG!G|nw|%AUuxW6^cFCEcHg*E zwLyXx|1dFenp$mi_$^y-M>IIIRKi} zB$*LOGciE3)=m!8Xl?!^a1*_o@24W0P=stXbF(JKJxFpfhzrluijHnxLS?_V`CbaH z(&kl6b3#7y#+i_z2m~{W-{Q*v;h4L5rMZBw!HedVK6ndsomJ{b$fzDWJqu8pUqlWU z@JW&LE7+tyKZty;$4`s=?<1f0zSGAL)8-3j=Hs)#GWG4WHPA*qF1gHm@K*^Znly7I zjT7qtCE+t)LKBhJ7O1sz%7ItTcgwe-iRuK0y0Wm`O2LIdAb!oFaL$?R6)&*F?Rr)n`;&eVN*Y+yBqOl{EilX|G2hJgrBZ zw`lftZc71%F4~yM$`l6uIyY$h!4D!+HR^*J?Y|SW?FVS1M;bLJapr#rn|_wtwEf_< z$UpNr)t*%$H>rej?e)FL;B-#6px~(NwF2TINybiZM4-~kvh>qvEMO7*#eW2x`M#*=ff#Ub&JeWMJz78`e)g&liS#}b=UB;>tBI5lXSDBaElwcbL2 zk&*<5FKOUG9h{PnAUliZx1fuOGoKmd_MNt_1Rhv_FKOrFBR7yCa3xa9kvCELJM!4m z)(gTm6PKkO8-A3WbEYXhZ^KU#%i(5XLPd4IlYAXT&H-zpv=}UPatDYUNZg2pe87>p zg+_&ul4m*QFF^dv3w%7l>`YrasnSm%=gdhiA5E_ZFgCMT6|Gw?#{wvMdD=P%3|RNP z%vQAEnb~~(nEAt-Fl8Edgq^3Y%^b^q@Gij8RyR`U8)%etNfqLd7%oxzCP(JGFbXsm z`djkfAlMqpJZ`lipzFA`P{t-oUx62U=Ch*x($+VcxfBbJTVFwpIA^iPdb;E^z|bER z`srxqvl!A&C!l;e--TS*e?3|~cIO7#flXMBRgZPuxvy+a9(GH}bH8%~wttJTj1v6L z{D8EikJnyN-u`vh0=Qw8GW*wkg{ac<;nP^@6sPXM%2e3b9CH5}b3iqbIo7{n_WS&B!gVi=)sCE-X@-IK?vy8dyUk?=G zU+sc}&-+H)tSoWu@V`P63qAo&j8}Axk}mukj$+>>X3NL+&xYq>*}9-UXV3@nNA(Y0 z&KPzTxCRn)+^I2+Nb*4$>xCqzy`e3e;Dfmxg(?F4Pa(et<#qX+N&Y-hs@{hkc)#Un zZVOh*7Q~wPM1|ho=W4HZVvND+-|nTFp&7ks#*B1pI6uhy50|OU^&XP&ei+@sG4eZ^ z*Y0^r)ROlXSq{b}`=^lilPHhssv1w&)cTU-UQR9X+C?;9ovnG5{v`T$WZ5ETlddiQ z-T2YW6_TeLRWUqI@u!#kb`jU-^$j<>Qr}7L^uwIK3WpZ<;P-{<8&WI-?$O>@O(pRJXYk+ciH?Ko{B-BqtNQnGxxekerp?QVfbG@hIUV|BN{Ja-p^9Wc0>>cQZYIq^*sz*dp(pr+I3) zhh;Z-u6E5o;UNWLsivsMl zKrfh8Xg#*PkulBxpo!z7)`bM(N<;pJGN>y(MS5b{4F-M_%L=6&=io+iJ<0Gz89pP! zCuI1D4DXlW-7?%G!!8+amtnmO*U9iI87`Dzp$yN#L*V>n_@WG-k>L|Ee1wOpzSLE^ zyL=}cOupkp8(^?#>>c^BDb_=eyecveW3+G`!6+g;cuXs?QgU05W@aOYwrVTHcGVq} zO#K9ND4vpJ{vKU5;{Zst$kXYJo&b>C0J;vXs0D5P5>VR9efN4N8o(OOaE)I?ucYVf z0)_-KXsw=o<>IqzYqPVNQ>LqASeug{$VsaY2UH^8m%Hz3`rYuIX~5T5-?TB_dwY1G zOX-XzVz*SShZn40waHqZXpf3e&k?cFvdQ5Z-XW21li>wPuXgkzokvg5t|-N{HW)|=SptZ4CVMIOJJ_Jm_yk%7I=Sg^l4 ztQK$D?rE;~H|N0KHyCk72I6t&K$kP#+uh&W)r)tRLSbh`z~9u;!YQ>5B&Nh_ z)vy?A?ZN9#;dnBVaN<>{#K3?v-WQBS5aTaGg`>zsb;6y_ind0#Dn(oW?*4(jvUXf< zr7xK1L1inJZ*(q;)7w+a;uXufS2&k-FLydCV&TM|U}Q5A=)jMioS694k0&N}A&lVO zkNaNS58`fsUiPlsyRL>_!b|JPsWu4BBeTi_~8B92X8Wq`WdbvPsAOTux z$-TXa9%l$IfjO%Nmkl!DsdbOW!^zG8C@(S)3KDO6kt{I~8i+X2hH(Nc>#S7AtLe&h z^d``bw}-RwRk_snoz!%os#cBiustVzIA=UO>o(%&rfX}B`Si9<_VwUh#`M!U>6dcS zwR?>CgZqr>Xil2t^eabBx-2JMm7A_I(yz+lKYpb#e`t|0eMp#TIq9u+bsL=(gX`BR>uOd;2jabhFx8%wvGAU%70xZmUi7<;eNI^Y)*UN%!0KT` zAB6cWcdoCjuB1)7cQ2y`;Okp(vv#~jhVV)}JuE=H3gJH7#fT3fd}IM*3lKky@Oj)7 zh|@cndGPAIh&vE2$K8W?6~axpqlnicbm2}Q9zghKxCap*Mfh#p2M`}exNae1_Yyur z1@{Apwz5aV?zyfhB1r}DYMTQ*+?KWn&T*7Qsv)T)z)&~`wSFOy-74E-|flHq_<_WcV!^ zz9hp}WO!bNg$D)wr82CMp;`yGOz)CmM23ShyjzC%%kWVdep80e$nXUj{!E4$8NMmQ zw`Eue{nF)-VVMk<%J3Q)*2wS%8G2>dEW=$g?2@6N%GkT@AvE#dr9Db4?rqPhg z`M!Qg9gJWdl`H6xe1AB&#{_2e1$>bhz>0ey)<-L7PAnW_4;C~hB3NqHC;R!bvNhNd z3A4W>Xk9Rxz;d*104l*RU>+uze_&vDGO8j&S+RYLeVKCPVzjM)Z*MVP`aQIcuhz}LIeGKcs@CviV_belwdTfB=$wajD-Xw8AnaT&H(&jrUXNMosoWa z2V#BkZY4a}3;9Nv5)!e0XG$0S;tD>Rg_DL_`dBDW8R+K-vkHP81F;0VtN`YTbvI*I z7l@J@3%a7Q-u^@va}{*O!l2Ml(6twajM)AH+R`BG0|kBIzEBjc^SJ`rISEGKRTjh( zu}HWdJHHg`5A{XaPYU*^A`Y!NY4ZN#?{}vj+vYh2{No@ST6_-2fEA%995z;a$~e_EC^wf(n9J0REw+<%VSGV~%|u`XZ>5Vu*jHnutI zs;?6ptIm~uiDZ9xb7&wIUX4UB7V6pDkIno3pmSxn`qzXk_3r8)SlQbNPuID!s{{MC zop?~OGSb`89SQ-0%y=Rg+PxC{x8!ueoh`1cT$TM7kA+qNc_rW2T_sA&V0C4P)ot7b zm#=&8`s%7(a=RGO>@DMjvS%ININrti@6w2=_;_lvlG9kTdY7ONM+@q*6oz_&F_up+ z_~zMWMF#r2@%#w?lKtca;rR$0C*)Z590C+1@gI-almxSETQMJn3-%HrN_UhgL@aMs zya)bR4xs`o70*u+Mu8wo0IQ7zu-cmVe~~-OC_;e{&Iq*Fv^1|ro}+*Z+BuLUuRPCI zpvDRc@aQa_vhX3E`33&}FS1bJZ1=|SAS>@`K}IdQSIbx-3ac5>?mjdU%Uf-kPYhM?UKM_w zrIfg+@PT+V5=_v7hvjXuEV?S6Bz-7LfPpw3U$H!w$Wx19{ldZZCU9TygRu6zZRU*L ze#!`lj6!()9g*F5&c*WAUP=tnN_c9Qq(`7i2rH=GFe~`bg3XjO5XCC6n_1sGm$XMo zT0U8;i>VPPNo`_XrzHVl){Q)AwUq!T|2L>tq0$-L7wPTpfkoWDkQY@tb;E!#}x$%HM&Z40Ibohv;NooM}Q=9!nf)0 zZ#iB7d@dG17=#9*N-)yRW)*O|SW@^iD_*zmA5hd>q%gkF5)6Bbbvc{Qhr{yxrmhe4##@~pHd1|dF2TShmeXO|XpB%dj z8JkZ7N72vh`=MJlpHx!x^ChH=g8BUe*lOtRXGN!qNb@$9UycGgEg;8PP0>$mj}e`u zcwVm1Q(ji|(&a>h%@?Vct=|Mn0kaWDit-^TpXF1@OE90%zRExhT_m1}vwJK>uiE}; z4vEv*$%_7^M93Bi2U$^uCkp1rdwRPtSzyR7I?X{g3BvS-(XHrTIk0$sAD;S)1$@z& zk~cupAwYN@&5C}-k;>QOqdSF@WHEfhHmz^0c>HP{~>NXGeCLulbRE4oymlvzqU z@V*R+QYT?Wiv)PFrL>FplFLNei8KhYqRU0P9BG(0D_Shl6@=dbvP(pI1=67&q~9ab zRY=Eg!}e3r6#`HL(a;1KrHYmc$a+gDIAR~P=)D54$x;fI1Sl7PS^!pcR5ZFhaRTKz2$9aIO`QU6xX8ykaN`k-@N{ z6$0F@gS$|V6_(4W0XualhF`V7Rg~3Z%o2sJqnrq;Cbrj#)>sx@iB1*e5bO*xK$a3@ z&{B#~s8dMVT{GM!Bz}4L9bNQ8K&sN3l33%{gRb$;vm`n9i zEgoeGtUM!DOTh1IB}y$UU(Zp?*85#sIh&SNm*39{bc}{3yr^u=N_!fbnr~7Xd@T*G z);g~u3KZ%H^=*);t|6ef8r{m4W>+JS)~v?-tO-3C#=072n;xU3iG*xnMLB3Le_IwS zHe1hj)z!5%wE11F9;K#t;MS}a5XWz4kr43v=(xiLkGK?+P0|Rc{*6dZVIsZI#fjl^b#E! zaJiKhZ&P!tQs35C*XnC(WDAVB&7Rh_=EfFQs)OsB+M1R3x1pWA+?W1Zrq<`|59Ei*zt4%hy=v_SCV< zbf~Yf)w9*pthnn@!owS&gYbH~HM8ccs3mS#i1D&1{LD+k*EW z6(8Ci{~Fe;rj}sunId~VyF$+qWPz?U1z@^FyN=s~Q^%3b($d-touC!2)U(hdTz7lxBM~CJ(&|#CJT2TvIs^gP7T3p_G_Ff~b&fn^0}oxu2}6yqUa4zp+>XX*X=D|89!cc&@n)#^p>oTOSuI&v z*BGzh5E0J~O)dUm!d>#NqRzm8a8jA(3aVJr0Pt+1wMF|xHNEu;x_G(TIZV-T>d zQPrrw2_^+o@HN2xDyPC~X>Eels%Wc>XaQH=F+oV{vEEHT9kUsYM292KLsYvw&)0= z$5H3^dm34tp3&m<)wfnNw+^}4Lqo&PR!r-P;MM469z7o;M?(|TE4w5OX{=t)u6Ln> z3)Qo&Iyh_aRdzJ{T0QusnKtwCfvKTd+3s^Guw9>?)7V6#MZo22c40bV@7Hrw7lE7* zG1+g+%9JwR$j1ieH|KbL!s%$xvt)%xeXLOj3#0Zo$!WNSHR*X|PCM(oTeq-)5r`U9 zu^V+5)kD}jjbp4?&k?pK`vN8*%5KrKrKbXgx_x{Oh2Ck#f8HFR4bfUdAZ&+?=B*iL498h+`Y!4u@(<__sea*weq9Hci0;Hy7mSxC;J z@Fr;sI@ggRq?j(B`{vl6qY1!cl zNOzC}xY&60i^O(;rF5r-1I$I!#a@xOkffSD2th` zTd10D3i9lA6y)2tP*7lR@lj~CyLnh>$D9H{3w+Z$f76yN9<;px*z7loND(MEDl#$K z-s*2rwl=kHalssU$vJi(obsI_QEc~nwz@Dd@T?Mh_9O=f5#w)bQ-Ctz79!CC8${Qq zw8M^HZMdX+KF>~bU%jsx{hKo9i`wnv^CTyI3CG~k1$NJN@TU?yU25MVXtuzkgDbD+ zTxxGZral9b8q!v5vAjLT`fC2@Xh9A z!L~Ft;%yW^R!TZvi_Z^Nh09)&1>V-^hwbZV+Zr2S{(8D)+f7twbO94gac$qZwt6+2 zmz7oLYDACZCFW;=eRUp!!Bl)uDi%jNF*U2j(+v5rGRn$=!{*1LNQZ3o(6q2H3$kq; z);l@^<}A!mtSk$(Z9P^wSr`rOdRIer6&5)@xs48db6UuY!Dx{V=?Tp^QV?d z2VSD<4C1Y|qN1WwzUj|5IC}d-1N1=Agf&}W*=UR&Sfck>1@YPFt$ZvOy|tuh31Q$N zq-RR?8Z_XWj#>oFP;W(`H!dU{29pbapxb}1rkNWZzYjyd!irbT+YdOPZt~w% zXcdQ+QIV1jMYD_Y)!%ZJ{Uw1m66i$E&%5v#;s3A8GLJb5=UL`k^5rO0I%9a|j2nI>l3K3}UgQ@QWy5>6W%5%*v8_MsW>lky*wLK*f-wpmGHSk9aSJ~s= zDs7Da&w0O&UMh68I9FG$srr*t=bxO=m0kD+5TtIv{q_W=0t@D*@L(8kP#UfqWy->w zEMJZh1_UH-!|lM$ad_r_{2#(>gP91W=#62$C?+y~eIEZuFM{(O;2gRL&c6XCdJ!D@ zKxI3GnNFTc!np_?KX9lvG(Qq8#&!VWyhy1&;5aVAo!+Ue!maD@5u^gsP{wsy$Br#@(+U!X`V>p;3q&H=Ma*+GNOe0JNL3@H3;FX0M03`6mYOb5lhgU zj%YTm6n^!qLGaQZ{~ehFzM#(QdeEr?4uUCb5kzL~G&q&=lq-^pxaV7zgU2>XYL|M# z6#=N0`4$k&xhmx;Qv~MLYbnpcz~NN##45@F6VRbK{LTFXbQ)8-Ds{jyMRde)E)hg*yXq9wgyi~1{E`?Ur zkx0i=wJ`vY&<5rG1objrPf7>{`HcE0;$OBrIAEM+ePG9|JZZ9J*!ZTYh*yLPlTO0sfw1s)=Mr{jfFQSldDaZdJ-1?>J zISr7|Gk#pm$5ma?svWlTx)U9}yc$#M*N651mzo-cX zW1TaThgwI-Gl>r0fjpnrrg);{O zZ7OZ`apXWy$TP_-EaxvO&1=Cw1xDJ`FV$9`14y)&(jVT-&v6Z@SgIYi!{DiRPB+&5 zF?M)L)$?S&pR}LfY4YIcPuNek?T}n&P-!8Lb5eN-=Plrja+#gnhA_@^b*kE+{;Q8R zq!&dQ>{NpIju+yTn=c@@gO>(DggHUSfk{JHlvzK22OMIhU+=^=&T9H`=mca;wT-8d z=9S^?ZbVaU<5_@(ZImOHGsp39%+oeoFZ7~u#TBZ@h7=e*oE zwo{rzOemWeORQb&}-%K<}D`E^sBFq$BlnnWmpU{1P#@Cu0o@a}oMMKb=HBBsobgh7r&8~DstE+U)B1vDOO$=c{Je7ALQJ99K&vCpI*(%9kyxxh%9BO+_(x$4$AfD71 z>BM-c8e0Gyp|MH)F{zF9nl|{OMZ828!OyJXno7FSEThwCgE;R6&LI^?(}pNT+MuT? z#%pHUn53rC`zp}1F^P@I8Q-aCgZdtg1^T7V=CofaMkMjwUHlLpzY^1w!9I$bRxK8` zG1-Vj6z>PlVW|ya2af?lzuP39`3&8Sevurn&>&Rm2ylkbOuDc2JRnX3&dY#Qfuyi- zswu>km+GC&M~T{LaMa!{B&61%v*pWGGCX`It)ofEeIx@Jrk=Kb3StVGCm*HW2bqOd zNuFL10U+mU1gIEvpaS5KJ)5r&0Eg^(N}HF~Ql`jwcL&(!k;J_gB7VItJ+@P7c} z#f?ASij4g=qO>m1Azvp5ZXH6unj6Q4o1mjwovw|&Xr!610%}!WmP4xHYb~jckhNMX zJGDGDqP8;4Y{FWo2Ve@!x>V~u3l741jq?eis^i8zn&#mmC3>+Sq$ry0lfE+g9bOJ(O88)_skO#ahA4CnW z<{Z_3@5C}S2`yf=xE88y(XO=x`9{V|ZHpnTEeOZh!&NmqJ;k7v3GT#DZ+yI#mJ9S_< z)p3>qGGu_P1!T+sX$GVnua+6DS8wGP(OGhOZf7tNgxu}8FQ(PNbgeAs3$i*f?|4Dc zc&XNV7&u}i83Y2}q|CZhYdNO1P8WWcoP{8x3DlG>ymp7yp|43ng*n%d#Ni&@B%T$a ze@x=wXim_fkMn?W)}>me126AVPQFEbk3~mPdrCV%|2H}$il344z$pSR>fL4w{*uJO zbP1f#;=lQNT;kALB%hBqMmnmVf28SIe`iajrq(^6)m_ce!~e*-Q=3vtiZ=ZT48uI) zP@9sEEZTIfv9Y9Bq(jo2(4iACGa9u!wYF&YFPack{Uo6_;kO8%UoHXpSUNNPnCqmD zTGRF~xsR>2h4ut0idt~1)AwN2e#$C)se6}SSBuU;{R4Z90?hnj}`(hLK0uy&y ze*sM&k=D^pj)X{?KQtrmWhU+yFgzM~)kI9(3r*Y~oe_6hbr^W9ebdCf)5QI4xJf2>o|ji>)teRKQbfk#U}3b-jab=O{9PWM%)Wb++Q$pr=1Fe zJnLRCaX&F5?nKr=dF`_%?wd^9pD}SCpAmOj4;#6E)5Lv+iTk4_?k8u&{Y?}1$4%VJ zP26ekPs%K9{?v@PpEYrR%*1`MiTm9q?wJ{J&zQJBXyRUM;vV@A;{J+>`+X+v1t#vh zOx(}TsP3ms-0wAUzko5`V43UOI(NAjH;huk#}3kFocd9FZNK6ue06rYT-BmBxtHpP z3mjVS;0UE0pI=?4Xx{Q<&m!e}DbxDla-Dk;a-bsMMZy^`b)8#*dWm%|U#%FB)b+(D zwYpRG4&&k+kmo?&DeFGjj)!_wfF?8N^4qLZV1R1@C|9X;IAnbm1m9zpeNgbCdI33S z?WyW;Nao~E_N?Ee!%6fbb$IHJ&|!_HLu_>L-8}^IQguilQx*1uABQUPL<7xw@bf6t zw00W%A#xu9&Jes5{K+=e4UIIY>POHa99pI7I7nz~qEW=D%%tz_Nd2^fAG!~4@Gs|5 zcLFn-ekNHn$|p5`O+QoH*w>8u;paJIsfRrXSppZ)&liC+`bX$T(3xI8hfv@D2>rbF zN9bqgAEBS;H2s+OntJ$`X7O$_WESICSE2_W55<{AC}o_#+PMy=Xj8e*c37)BA~~13 z4=}B5h*jHa+5_R-`Mwret$xWhevK}(y6T@sX3csv3AOzMO&)dk;JOQ@k^gC38**J) zgVr&Q{NL0^emUA`8hc0FUo&xk*u;H-i95XmCFPOx4)u32ZkXF$?eEe5x;CwOT9tXS zIYsWtI;(t+kH^g z>O10o!o)pc;{J+>`%)A4p&4<1+QdC#;{K9}d!dQ@Ju~7yX5!vy;{Jk(`*} z$W!yMi95ZmYt;PMjJQ8+;=aPf{XrA=E)(|?Gva>8#J$|a{XP?Szlr!y%#Qpq?xZh*q{-%k0r-}QsChlypSefBzSFYDR zjZb^P#GTd`#?fY%iTe{K?zS0mA2M-&#l*eU#Ql(oyJJS&_nWxCWa92OalhBZy=+F@ z2Tj~xFmZRAxF<~9oipN|FmZp@#C?;A`!1ckTupookf~M^>MByFqpl*ecu5aUf4dJ% zb1suTL(<&qovb3MEVuA!R*|~Q>MAlzW?A>oPg8ew#qnQQubMZtdQG`XT6;hpSEpWW zT{o`UhK1e}FkYs5y`#~_2DKZ;mbEXb@@ONiKi3Y|(J3Xel+^s!G|l6?8tQL>@f&V+ zf9DwXZ4U8%;hcQ0>A%qGNPj=p9J%AM>TPQrN;IGxZKrd{9^ z(|-aRu6(=za)j5NaL5vj-37nI2`RUW?;cPt$l-FJ)LD=vdIGWv5Op3D5Dy@4B1&x` zAU6V{T8n`60YVq01Y|!TC!{?47^SQ zLKoB|xt|AQ43*OBbt&H-sKwWN2nX7TC_y@lR{YvR@Om$B)Y)7>ssK@a8v*eGqW+#p zKoo*#I#kb+70>mYQl2<)Xr-Xb^9exc67o>&uL$DEh8zQ=oqHE5ogV=5G}!7Idx_I= zX3;qZ2w9U(c|J_WSkrPq)R9eUqZ4oQqLgkMwZORt5UM3`@B%A+FM;xPJ%@qgH0b#b zK%&wk68gCZ5ZceyDSrkKb$?ah{4F5Q8tOF$h*9QoK%xd-89?X~@~CI)M)~s{Rb#&a zj=HBOc$Hvyt2MO6dkA8n>?R1tL;RucblnQbYjTVdkUfAL(&(sX{ED|nRPLVyj_M;p zhxEgehE^7kR0W+c0p}ir#=Zu~r~&c}Aav>Sya33(AfQ{qzX77#Az{zQ3vq`Hbe7XA zat0f70it@ILY`JY99q4IP7fgJ8yx~C4#*}0_fbFw4ZI#AItCs74In!~Pq&0IKo%S5 z{1lK11I}qc)Ms{r``ds-4HA~&^+0vyB5-d4A{%%5)+5?C# zp`ze-#`t0;U3zc28#qSDX8|cN)Z$4%RR2&={sAEEC`Ks(IRnU9O+uph79g;@EM7%u zD`vo11jrGCp06bwW1AvX4xr$ro>eX0Fj4D%6L8uEaVbv-kRb!*{eaX0N4L6<0it?? zq86V4M19XnK)wiwZinhY)}w}A`E4o%bYZ>X+;PSpFmV4lZ~}%_J_`uhj&45_fQ$n| zoCWt{{I)=S_enq&0dm+d6I~6+eHwQZW!D2jm)@J&02#u-BI=I$qL*gRD&XkcgM?#{ z@J>L~mAK&kF+iLsMJWM!1Q6qR_yizhhPrqrfzFMozHukGUjYbRloF8jfH;xT z>+S)h%Fu$HR0`-i_q~9qdoqH~rvOpk-w=?80TJ(1I3=&I0&>#Orq2SRz8fY={TL9x zp%$+a4g}D-{{fH(fv)Rk&VuZ@8^~-CATJnjt^y>YLAbXA>kR-`)Lo&eoJKbEAAL6W zpp;)LMU=Y%X*cNS!+^YIz_}L?qo?;7KpxfV&if90Eu+nU88|}*OE?OMcqd2I;W!|z z23{`#G77l>lzM(0knwC@A@b|!(pxznzj67dfzD<8!!wR7J+A>oANi@g2M`D-aTNX} z8P;N$(OQ6W!q8Jb0LU0h=@Q-nNT-4O2p|r_i1ZL3;|4m10Vy`v#0I4y^ z(*uZJcf$EIK-9fBQR;JmoH9`U3LrayD{Ov`bT0y$gk3oCgJ|8OK`3<;r4Az$HT@A% zm7U>^WVaH;!HwNG3`Hh;`@06zc(9`*7T%+#BE2}IS7LR==tN$bfRgCLO>}rRz8;U0 zb$dGlpxPJ4i4ople`f?oW8%l-3LRsJ_7}e%EU(0AllWSDrCP2x5lO^5aeB9cvynp} z&VRT*1=_y;KLRVB9Jm;kG=W@ZbjoxP=cslBae|7Hn=2#^MxzSUpZsP>awGoCm{oPPwPAEua7U$Lb#88kQvE;+Df++IwVJ9_&Y za+D>%d$^Z>Lv9)^cK0V0)FF%`vIqLrpB9_g$R85P502EiTr%cEOi}RBHT@hF(YFM! z69@OmqgN#OW`FfMYI=UG>p+*%Nhco2O5J|@?X0c=KcK7Ixw8)EG~i3EG1nGfWeBE; zmE3^R9U17r!PlMi>23prf6QAYqxMYWp$XIkz3AJwhdWu{J|%(=hwl+)nsto0XmoLw zIN!Z4&&rf%j86f_0iSfTL|+(Zqbkq_ecnmwj&}unBRH&yZEaENaHdgsFwqtEOrth*VF&v12kGi8cI&F~ZwHG~-v|qVlZS{3Erg|yOZ8#IB0cXm!c-q`_ zsFS~`PMmx}$E2CYIAxjwK&E!6O!h~5cZVbUK=5V_S zt8cebUFgUv)TOF=4GZ@r74iNf#l+jB%H-Wn(!=k}Nkz);@IGPesxGtgLvf~ND-oP- zgf>+6;yfeX*hB#52x|n?1}1n&DB6S{L#tslRf(!a6r63P4TIU=&R9uYv2m|#rx_EY zs*mQJEtqmNX-zpysmFP@0gp6@oaB~$jWjK*O5GYxNWA)in5(lB-*2JrAgo!>tfSLa zawvHQ!w?KO0gomXQ+)BpfqpX4U`HhE>#s}V1e^W@N6_eo`;&c`J$diNZ%ku2)CN;X z-#c|Ma=a39F$}H;z4x2-@;DQf!l4J~1l$8r(0hanq8r=v*@6Um@N^`m&z_PuHM9P* zvblHiSuPmr>x}dZM6uQ~O;#LFubfR>xzSQm}1iGX!L^fs{5OmzYQ?QXnfr=&I z>d0=Tt+3SAj^@t$AP$^Ba+Id8gS4m;h3p6PPd}e#lr@E5DMuvE^Xz2C>>w4PhBud z$D>Mb8wKLR`&8hjboY~g&W8)Rc*OG|-ko6L@c~R;G}^)i?qpLA*pq49hch}=oly1V zlg#PNmXClyg~ae}RI6L#YmMtee`2u51C^+K6)bPP$|Ok3658I7;zMFl1|8nH;n z`Wu4h>;z!M#3Elc*HBKkgY0r-)5j@QQ-){0&NoxrPxOMU@tnj|_k)e@AZ*;|`>8YpH~DivRE>O( z9E##8szl6kx2KpVxDZ6guw>W#Ek5C8J5Rz@No46tccd^HWqT(WGLz`Y`!Hb+?C!+FWTn}Up=oEcMmzKJn*p4-B zEeh3TIiQpG&+N9#+E3-S$C-(mpbPeg`mjf399px62feSUZoQDexCm73UCeOVzAa83 z#a5cq6$y3=ry868yW@%7N*}F=b4EWoatfnWhkzbmKl%tAosH&d$zBHO&8Inf#-RvJ z0w!Ew^k`Im$^|O9s8jmqBF|hmp$S8G5Ta9)8fP87J@6_V?U1UgA^vP%OHSubOt&7G f%z3!DPek(TI#hjIO&GDotIkCU%}vPZV(k9_DskUB literal 0 HcmV?d00001 diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeRCCompiler.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeRCCompiler.cmake new file mode 100644 index 0000000..9a9eb15 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeRCCompiler.cmake @@ -0,0 +1,6 @@ +set(CMAKE_RC_COMPILER "C:/BC/C/mingw64/bin/windres.exe") +set(CMAKE_RC_COMPILER_ARG1 "") +set(CMAKE_RC_COMPILER_LOADED 1) +set(CMAKE_RC_SOURCE_FILE_EXTENSIONS rc;RC) +set(CMAKE_RC_OUTPUT_EXTENSION .obj) +set(CMAKE_RC_COMPILER_ENV_VAR "RC") diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeSystem.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeSystem.cmake new file mode 100644 index 0000000..1bcc695 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Windows-10.0.19041") +set(CMAKE_HOST_SYSTEM_NAME "Windows") +set(CMAKE_HOST_SYSTEM_VERSION "10.0.19041") +set(CMAKE_HOST_SYSTEM_PROCESSOR "AMD64") + + + +set(CMAKE_SYSTEM "Windows-10.0.19041") +set(CMAKE_SYSTEM_NAME "Windows") +set(CMAKE_SYSTEM_VERSION "10.0.19041") +set(CMAKE_SYSTEM_PROCESSOR "AMD64") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/CMakeCCompilerId.c b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/CMakeCCompilerId.c new file mode 100644 index 0000000..c126ec7 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/CMakeCCompilerId.c @@ -0,0 +1,691 @@ +#ifdef __cplusplus +# error "A C++ compiler has been selected for C." +#endif + +#if defined(__18CXX) +# define ID_VOID_MAIN +#endif +#if defined(__CLASSIC_C__) +/* cv-qualifiers did not exist in K&R C */ +# define const +# define volatile +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# if defined(__GNUC__) +# define SIMULATE_ID "GNU" +# endif + /* __INTEL_COMPILER = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +# elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_C) +# define COMPILER_ID "SunPro" +# if __SUNPRO_C >= 0x5100 + /* __SUNPRO_C = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# endif + +#elif defined(__HP_cc) +# define COMPILER_ID "HP" + /* __HP_cc = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_cc % 100) + +#elif defined(__DECC) +# define COMPILER_ID "Compaq" + /* __DECC_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECC_VER % 10000) + +#elif defined(__IBMC__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__ibmxl__) && defined(__clang__) +# define COMPILER_ID "XLClang" +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) + + +#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800 +# define COMPILER_ID "XL" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800 +# define COMPILER_ID "VisualAge" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) +# define COMPILER_ID "Fujitsu" + +#elif defined(__ghs__) +# define COMPILER_ID "GHS" +/* __GHS_VERSION_NUMBER = VVVVRP */ +# ifdef __GHS_VERSION_NUMBER +# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) +# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) +# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) +# endif + +#elif defined(__TINYC__) +# define COMPILER_ID "TinyCC" + +#elif defined(__BCC__) +# define COMPILER_ID "Bruce" + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__ARMCC_VERSION) && !defined(__clang__) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) +# define COMPILER_ID "ARMClang" + # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) +# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) +# define COMPILER_ID "GNU" +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) && defined(__ICCARM__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__)) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) +# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) +# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + +#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC) +# define COMPILER_ID "SDCC" +# if defined(__SDCC_VERSION_MAJOR) +# define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR) +# define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR) +# define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH) +# else + /* SDCC = VRP */ +# define COMPILER_VERSION_MAJOR DEC(SDCC/100) +# define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10) +# define COMPILER_VERSION_PATCH DEC(SDCC % 10) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(_CRAYC) || defined(__cray__) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#elif defined(__INTEGRITY) +# if defined(INT_178B) +# define PLATFORM_ID "Integrity178" + +# else /* regular Integrity */ +# define PLATFORM_ID "Integrity" +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCRX__) +# define ARCHITECTURE_ID "RX" + +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + +# elif defined(__ICCRISCV__) +# define ARCHITECTURE_ID "RISCV" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__ICCV850__) +# define ARCHITECTURE_ID "V850" + +# elif defined(__ICC8051__) +# define ARCHITECTURE_ID "8051" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__ghs__) +# if defined(__PPC64__) +# define ARCHITECTURE_ID "PPC64" + +# elif defined(__ppc__) +# define ARCHITECTURE_ID "PPC" + +# elif defined(__ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__x86_64__) +# define ARCHITECTURE_ID "x64" + +# elif defined(__i386__) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +#if !defined(__STDC__) +# if (defined(_MSC_VER) && !defined(__clang__)) \ + || (defined(__ibmxl__) || defined(__IBMC__)) +# define C_DIALECT "90" +# else +# define C_DIALECT +# endif +#elif __STDC_VERSION__ >= 201000L +# define C_DIALECT "11" +#elif __STDC_VERSION__ >= 199901L +# define C_DIALECT "99" +#else +# define C_DIALECT "90" +#endif +const char* info_language_dialect_default = + "INFO" ":" "dialect_default[" C_DIALECT "]"; + +/*--------------------------------------------------------------------------*/ + +#ifdef ID_VOID_MAIN +void main() {} +#else +# if defined(__CLASSIC_C__) +int main(argc, argv) int argc; char *argv[]; +# else +int main(int argc, char* argv[]) +# endif +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; + require += info_arch[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(_CRAYC) || defined(__cray__) + require += info_cray[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} +#endif diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe new file mode 100644 index 0000000000000000000000000000000000000000..b3612930ea6d8e5e58ab456035a921d292a66c6a GIT binary patch literal 54020 zcmeHw4SZZxnfI9_lTO;Cla{6gXl1A=q}ZlOo0b+@%``LV9Xk0SAElJy&15q9u#?F! zA8iU<4WtFeAsP``U2*Ly>&q(ocHd>OsOzSDwJ5p)(Pb5-D6&(FSP^T*u6h5@Ip^Lx zcW#nGe!Kfy-`D%g%{k{e&v~BbJm)#j`M7uPY1}!+@)=_VxF;tWJA#m|I{ts=f5XV0 zf9coevxkembJ-D_|2vnp_w~nJ(b!;bEHK~-1|pHcgsUs$iX|hi{)o%d+~yh>><(3x zl+3M=q+7gHD+JH|fS$@&=kC^4`VX1*8qQ=Q4I;5yDa`R7d|rJWt3? zNjpP=E|-l1uei*{>jeM@i?S5uMD!pFBJhS8YndaW{C^8$QAs)rI&Jhs9b=VKTC%9??NvInOI8*SP9fbzRkvz#AdQ<5h_;=UYnf zL%0d=YTQ{D;jOL}fEEf4<0iaKlrS#nZ_DbMjU3>(6u~%d7w-4s&bsPY>6X=NYdFM5 zdO3lc=)E6z*2VE^*Kx=)%0G>p+O`vS*2VGGUBw{^{|};s-<^eoXdSEDvihoO4*WFz zFO_&b9HjpvdU|4-$m7mSJ&g5KIWIlHF_e+lDwVYT=TKA4bH^Cf3dvWI)DtJO6Axu4 zKDrj9ZrjkfGqD4OZbMe8?DHyPX?ActvF=f-O6Kv4@o)VlM7HcwV5AqON;3_xPL!Bj z!`R3MTViL;xH9rYC1hidk_4HLpwOwOotM@zC8%stY{zfgK#n8%Dd$&}@}Ap%KhKuf zNI_om&XFTjk@?O$Zke2%Oy6}DiJIpQKJEO(V<-CnQASHn!qhU)+kmCGE>VW$_h zIQR`HF{GpmmQ(X9>7`+)tmcfA!jZE!=K(UvbRp_{;AX^**-zcXc&p3oasUth(s`f;A?ooNSi6#D zpp+=~){K7*P*(Hw-JPUU4@n9uV*_8*gznI%v_rWeWw zu}+?Ee;H<*Sp;~^(}Hwz$thK{#{TUg_a2b>O+=f>Re8_6*by&6CBDcUno=`@zqXo`W_{EI#9@*kwBc*_rd; zukk-+KeYteiL&j4oI)2#mt2Er%Dxf*VI~J2 z2eEY7yD9Zta$aUVn5FGYkW_Aag6!b-hj%L~rA2Zrh`X@4f;gB*HgJ0$! z&rME_QO6>uQD^mMza<`!3#h*Ur_8~b@H4+FgQCzS?j3hNGXA?4IN33A!NzH1JNZ0! z4R!2s3D<%SCG~U2SeWH9 zzfA@I;8bvdI9e9KFztM#pj4-_V`}VkkiYsSDX7%nI-tsaymWE`rdC0K(H4i2u5&1< zvNB4-UHnYc-OxWg6(1o=f~$zaf|0i-Qxl1e=u58DVkhWyNF4XyVzk)Dn{y zC?lsF%EsR$e+$)p5LzROH@^Sm$Nxya6%OxIUTVTKT4%d0RH-p%iGP(TcyI~>PRWojG5$RpgB5;;3!O18`)_m@zRiAnf zVjCYr)L-G6Ec>?)P;Cl z;E)tznku_4hd1|U%GaK`$@N?h%uPA6RtkRV+lGER&>-C6qDtz!(D2# z-hg1V;{|wXCG~HUW!nf$uKx3=GBQs1Qb&EM7f1^mNDCD;iOz?G|;pp~4xJ%_oQ2`t0-8g0cIk}p&JyK58yr&V3i|E@|J$Wm1sKL!@ zkaI<%qRzQue?^POxdIM3uPJ|*k$#lYej~k_ z@HZh%Hu9sNnf-y1I*wM&*4J?pg6=O`l;FDj8{vA+D5-BNsqgz!$DAMOfgz!_ezlXE z|Hybb#;;Ok>6~DSvhOWZBny zI7R1ySCO0cRCq>P&W-%^4++Oerf%fKKPS6J?C%4%ZDi6BUr~4FSb_847%&e`CQ6-; zco`shcjY?|{w2{Kd7?!+z0}!}U)hv&yZtQ6!TR#g#$F!z_p>$QaPZ?8ApB))<5?wD zd_nB>Q^%G3buYsixR2Bk5eV!;$%+lI3?OL?w2cQOjJnlmSlV}wXeVuG^yk3E3@@#GG`p@5sYS1bAH za?((H1tz|p>hjFvPEPhAK$X-FGY=y25<$cfXLtI#-@Zbwmt zWA-1yCDDbM(;xuKiYJs&n)Ija$C2a5FtFmZGIDm#2k*oGdFjQ@j~oZ~!RMR@9zf{d z_^NYcA1dY_-Q)0$JTb?gUZoJ3(Z6`GamAayqp#&Rjds84I5k(y&wL|KInqr9?jr@n zGWAxv(4RWvx1G$lrMwSj-itX?Bqc1ST}!vezI7#^y;g zngY*P(k-RF)bEwF;=o#A&z}4V8Ug%h>2Vzhq_;aTp6AwFr=X{|t$-$3#_4K8Sk9l#|0W3Ap13;3IFj zoCiL{BX!P$ClJBp!hM8h*8bG*Fr)C>zJ&?ZgZ|VTnH`wC5k;=Mg~YL`AYJHuWIKA_ zNxv;K@)oAZj^r0S&ac{lkMfPF$9%Vai@5io&W%pxG2e>uM%!^el;%D{6V^;Vh@Sep zvGf9<`%)ABqPKwQbNVKvs!bC7;183NC#luOM&5EH*Lj?em>D6*d%(hno7AVN=zD>H zKJe9dqngLO4}w3-4pZEcwBz)%Y&_txQMOy7#((%gi?&%KHkoS! z5_SUoqsw1M|9;ekEU`D>Tk#qqr>dTsQ-uD2j{A7AC)Hb!R*F;G-pp6ve$Of+#~jLv zOsf7|Y8w)NbS2i%sx(>1Wk^1$96XbH18aY-4(Jc!`oQ0p%D``TVj#Vq)JH5&y+ZPl z6NQUkkj}%fm^ymf%gA=!_WSz!t?0kh!-c8#2~*uKP4zG`oOixS*}_ymOHne_bEBa~~e??wivbFvKu$7HV+5I0FOe)4Jr8oew_ zKZ!QZoI3+|Qv-x7L!Lm!$nnXOc{*6wzXYFxS!>hlF}^oNE56Z^XJLtxWuLtXI!rHp zfXouZ=UOGbY6)$0r8oaAa>mm0Ccm$wo|^nubb$FVu0)ZNu7@H1npT-NmZC`VMbJ7( z#rZ-|y$MUWdr(x2ZyLX}{aT>ZoH;n2`VMS7IS*SX694h9l|$EJV{o&uV>^q z{*fEVFt`$_r;#^V_LqYE{X`HZb#c0M#$MKQkuDuyuxTnm}A}!%u~;Ee}K`Mwv19`Ymjs51uh>AuLt0pS*)7Y zEtg;cl)NNuF9!xhS&-R^7CbeVuOBmicoU{fen;4O+Wtl>pAQ_o9k8_h6{OHN&?xDW z3B(~WrbOu*N;BVrQJ}fd-;%$AVBe$6WA+CT&~?oI1sR(xJAi5OsZWdcOWW@O98xSk zWj%JVCatu{b(%nX}GkL2`FEVcR@GycaPSL-?ou z54$lmbH8mPwwH^rj1v4#eV4Rk_-jR!cYf8q2-7fIx$~>OLR4wR$Vsepic|hk|M5ys zx~|x_al)TEy4OKoa^tgmX^XJZzwvnTXGA$`eITZdE-bDyAIm2to^|ZqjUAf@me5xB z)r~uoHz}!SGhS2xmA+01UJLP`73_BrdpGu06C3%?NWri&y8rRYQ*hRgS1KF-kXR-r zI7;dbS|6+ceZE7B6*>8&_p6Yk1`VJmG2f#30QUcu6MHvpwJWJ_C9g+SGLNCr!D^c? zShoox`BxnE*~Z<@ueKE8U)`dE&-q3@tUU3akzYU)i|&CYCMtWzNEiN%N3rh`bL3FGwFl)qxye)31iq*;2KEG^Q6W(BFP73Y!H&1RDxSJVGiagEz}S&{}l3v zP~MQgmE_M8r5b$L;rH8)=C)v!Y(cDvk5?M)eWvaT7kms>|4xN!hGtaIj2Stt;rt-) zZ!gxG>s=(_eK5L%<23JNiqrd;s3q?&vK)*{_D>=2KcYOUt7$yp(CSN)E1X*5wex7c zCR_6w{VDWcnq`ZeO}eh)cN0f5mr9-Y zWivhBq^*te*hR{1CwXe5h$*XhjOXtCcV)#<1;8CQm{#XwW0TA8+d*^V$>n#*aE}ao zWVl_14KiFW!^>s3ScZi%JafIE_o@tkAj79*_!SxcwG8i&;T{?G$gn|%>v^cPFZb7} zZ)Y(4Fw9&=7x|Q;4R!o;6=m? z9>dB#Wi)L)nwg6n+N!M-+f}zxGWA1@p?C_D`6qPMOesK`MV@?5#z+82(*U~Isyfg% zE&-*z-2b;Otf9mY0=B(Omq__tcp%hGlw8hKF+U z59g${&3%o?cjWH5mi}{S)_||6q510I;6SuL9E#nzwW$Ns;_S8>_{& zp-M(-v`F<$jF*Up1Bsr&*uagA{gJKLOJE=t?7LCMyZZy-P%xo(hk63ZaN@?AnjFSb zh`MAQk99^xD8YJgx_oN5j&MliJ7joH(yJRgPdQ1z9qUaFgdz!7_uxPP?=Xd8vB8+D z($n1N_BE|wdUm`&(whtiV*QDIuF5vwR^;)k87k`u5AJov0+HU3R=jz;x3$6FeEka6 z5{M*i?Q}TylxeWL!~af zij^1~bj1e(;V@$SMXXR1nW#>v+f~`ol<4%2ci?{;6QHG)+}oe%a|Q7dnyY$f`49u1 zR`+N;lrUHu8P<1L|Vd`&LxeJd>;t*+Ce zJRHtRm*)7}sMn02n;w^b+8}DizyEe~`iY$Mi#h4KJ!br&edcsDC(UyDRcTJTJSSb9 zlWwUt)346qU%kwnf8wH?wCvwZUZpwZ>!N1-vpM*0=A=*Oq_@`BU+tUvl`Z0G|pzZI?xRdAA;RR4oQ%*AcEStnj2 zLwFgU?iCTB2MpQ=3&;QAYO`a1@1n?s}XL(9Ywqj zp&NGs@fL)?z&(WcX@tucGj@RR5#ERUZp05E{Ab*sM0_0KG2HhfK7sIixDO$I0^uVU zGWG!BAUuKz^1~EI_$%B`AbuKQ@FK>ZK|G2uj{60~hY=pd{UYKM6ykmb@e>rsA}T|1 zgg?X00-%HNP22^Dvr7=-b|7Ag@W)t$mm_`x;ioT!P7ptYuP zLilCe_Y)4nib}>FM7$bd1ovUYqX=KZeFX6n2rtCQGLE0{HR;-^i>xqTH(QzoZSRYP0^I_#&+ZD_$)9X$8xPg<|afg4RSBOTC6_3>= zL%+CUY@3afhFS(#Fi#zfaD+Jpfv&+=f?Zqy^TfKBu`3Eh$*T)`qOtx+qKCN)dSW3^ zXe{X23qwY1e*tYN5cYwBfzUuOiq`pD0qtA_!i;^jAfAYYLlNxEQY;c2h_W9R?9s?k z7ajhuySI5;o4o$DYpS}#kOlK&@cOU52jY8zv4qBvxc=!~)eGvT6uPujz{eL)ov-b` zjh9cIKPAyW1OKdnKWpHBga)ugXL(!_2mc?vvW|yq_r^_JQ8rN>ec?5k)_=|k-=5{-I(dRR`qmY-?SSK3RZ>tyLy8`K#&Xf{)@+gtAV_VZ>+8sC1tRtD#+@u-i0Y&@7@hH)w|?&Euz_5wh495 zdcJYHi}T;56VveV)M6EsLNIu>^7jP&C94gMt~Gzr4< z2~3=jV>faLP>{s`Xdks$i``AL-(+}rM3(9qqN;|JO59dbd0?y2$aigi$BXV|Cay%coqsK z+x;;-NXolHkkN|n)iYL#!dgbOcL0sV^48cE5tuPGY!_Xg zPm+E%OMt;R9v`thx5(3qVg16v4Hob~-~+JsylvKu{s?8Xh>Swa_`AZp@tld}ue*>K zqLuK}EJ=?b)gV?-{UKKH7mGGi&R`U)z+Ps5_k7YGC29F&uPLTRpd_`4eZ8IpgxRm= zNxP#2IQhRpy$aRtz`k&QZyzk;mc_iN+8s}H^#|gt@YV}&BU&mw*qqg6^sctu@lE`ncQ5{Z2X`_31MqtYN(6T3W;SQN^A!N> zj$h#aJgVLw5#hL^K%q`ojShk}nsv_C7k&XqA}4gS0sm&{^MKFC0tilMFscT^y=+ba zw~M8PKe1!eKQgFlxk$mk&=L%Ludz^6#Z%gz{vowSr6-&$FB?`XVENgw4FXo+3=e{p zEM?~@R_IJdVuN8Uk5$TLbDVp)KNTs5GmQNLE?p7JuZCQX-=n2pN2HYH{|v!gI18+7 zrL1x0*kQYvvL$?vk?|Fgu|TU8(vNzXAmeT0oAo+M*vi9wItP@w{54r>v~##Y>0=TPRX5+rI&n z0_Gr&6y+`{pXF1@3oxG0zRF+>T_m1}v%73XuR4A_kHqQjW<~#AB4i7P0<0**69o(7 zef>QcEa38sPI8b#f-t^>{1qjcBS!QpLjV{yiA> zSkdboqjKTE;GQ^?a(WI`dlMyZLGsr;S+@{x6!eBbGY-wX!6|qMC8R>L{e!INHyoz$ zVqIahX#kb@EeHA+!bBzHOv#*LJb&YmI0jSj|2+roTG$g+i6ATb125G_072#)#|RTZ zmiZ%x3@sWM7?OpUjh8yWL86$=RFkisN77Yyy$dYzZ@{^19Wq~dv?ccxX z79CV*DYSbD6nSSC_44f)s0b|*WJRR{ey&WyqoJ4@3c~rWhG(Oc`Y&qtsSLP9&5F_NiUi ztJ%$p7K@xkVAD^g8i<4jlX32A2rU$6MHdQ`a$8v!-d90U>Lje_A^~1vE9>FC{5|liFB|J>34~AHPZ2$vHetZsQ}bMG&BLcRM9d4 z*C+iP4zcmEHz5CdDUsK^2}ImEq-4+QEFrPMvhjt z!SCM6*|fF0{eD(pU^F)4#bbL`+S}ONdV|{NYio43*DI#1#unAxET3Va^&09OXYDXJoqqbgFY-D>|e3tAIBb%z~_qtJLz5#6MXj9Zit|sO* zz(n7V)<1wZSbOzNi$o#P2L7yJ{G8&F?UyLYR%RrNHWgqJr!8@t5F zZ*FN<-CH}@5(DJk-t6;`-qnWYR@LqCw6di}ZX4b|RDEc7{A*mhhFXHXYntp0>{25~ zkOjKh+yc`j+V$KXTn3J8mbUg*=mf2BnURGa;r8PNNiWrXJ32JSfexEh&5GLCG6SE~ z(dJef*t^ZJdVjlzRhVI0+SzggA_Q%4`#}M2flIoj(Z?>&Lh)SN(bleZG{L<6>4xZAW9YHL*$~k0erjycrsNsN4#3R$ErqmFBF5hE}h)g}ujsdUv#|8>-iC zxQbZ8M>Ms!v6V*lR#;Q3@N8{r8)*U^&CgaD7zFHS(lqLChDpH`e2uWbs_C%W+M8ju z8ro_zT8q1W8`?&;Ak|&RtTtn|-_YXqd)puw(Q9Kh=4_IsTHSJk+Ong$m8~%{$&_0m zH2f@CK%3g$tZs+3ubly>2|qO4Y2{(9q~s>lM6e+{QL#XYW|EZvAx4zIg^jbIZTigb8+fOTW*QL(DX5sWWn< zm%ZNCu8?zutXAo7#X;4Pzkcr^3Y976U=_IO_ad;`X(=F&wdLjT~)?K$8$L*l)|qlrmn&eFO7ba}=MLbTk@S zvO=Uj)?|Q%QTv1CRozYv-OUpbcBF4?_mRfjh|F#r%+`x3pdFZjsYL4&Y+r)h`m;4VH2`EhfNR zG(+r_d5cM^xkI3?FWRsWVnx^FEhYjNs@-@!LdC;>HGyaGDqhSFsRDnXCxrJbSkVo6 zC4U1NcE?`)UmOedszL1R=+o#c?S&8G4OeGVv#>Je#Jq*7>7gLcSx-T}a|;Cp&Nd%~ zcBhAjg-(nq0JLFlTJLY(vc-$G7XXLzIuR)XBFRa zhe#AV{obu^I0l|o;>;f8FhPX>ZEtR&OiT-rXoC%+>r=YaiC;~)<@9`klg7RVUn}}I zWiAx8+rh_4PWl3l!J~_u-tFK|C3w2bxkb=y!;B77c_ZgSXJexjv|N)#FLqIuKsxYZ zDU}YmL;}z;1h*xqe!Ib9X;!{o=v~f6ciT3Vi^)a2Q~-F~VO4IJv;nHeEM^Us zR|cfXtGNA`7Z+v0+OS@`VN0vev(<}5l!2?b+phOwZZvmuyVT3FMi^FPD_U|Pegt56Z&s9-4dPxq7Q-Gpe`=|A;U&860Nz?FDk>`DoBn)* zqd$UQ+TnSC1#7Ora*&T6Tx#@K74f;~t=yN3-da+$lrZoRQa)?s&+rO5uJiG(H}6(H zV&s2{a7yj;!dU_nJH+Q`asBBc9`)tZPyfQ9A(wd2mshF-v}b@W9b$S&SX!Vq(6d2K z+rTk^j=zHh*Wh_E_db&>|2>G~=~r|x8l+bYu@}|F=AE-GCLF+n;adbKFOP!?=*>8l zp2QVjS-KDp+#I`scqi^sdeX&b>V6+wzsibNFW3(_pdOmPYtU*AEvF(S8;j-^zBY72U z-n{oBiN}DKGv5VxxU!h#JFcF0&Ag5CC~0>Bfg**qS@8E=v zA5426&^^EO_B{9e^5Oi*{L*pve8*!F@z24Zqz2xGyUO-|t92j$U-Nz)y;SIKbFHab zTm2`g&ObS!t9tMYAV`f54zWK@Vkod-Yzhs9@CK#nx=yBS%*FDhk1!!1aWn2x+#H8z z?x+74Q7{sr6umKQ6vaTsug~Lu>3MLT29E1IIKKkUX^d<$@uCk%o&ds3I8}sm9y)&D zP;F>@BwCDJ56GeOlo|le*m=0qJC)VA4IO>~sfigV<2}YGNkEzx^6+;ek)mm-4hbT` zTsnkO-vnj4j9MHAWNZdrg#9z%4C6K={4G+|=P5;}G}N63rw%wk$&%+BGRC=b`*v;Iy0v=M~@#p9kkH;6%@ZQ;HfK1`cT+ z=(v^v@-T;x+*M&U6zSf}p3xzMvl2Kb^isgV7DX&UZ#tsc^iufMuMWXWd;E7~)GG~M z*GTRNrtQlCWR8Q*bU0P=lq-^pxaZqefX6mU>X&xH6#=N0`8E*DxvJzTQv~MLYpck? zz~NN##45@F6VRbM8i3~hV8~B-^)JAYOVdvnV4)wvA&TbfQE3T+*Za(wNNGB}9dTh%Sgn%Mat7}wK;ZNYI*e9rT)Uxm zy?&gWkmLu%9f~wO039cF2sh>D_5!jg{62uU*dbFXJF2K#ly0j+9-{LvC^-kWacS*E zrG%}LjhP$Y+Fs`NBx+h)96(&Og>|DwYYS>G(H0em72!56P0t?&Naz_qCFWk#P_$-; zJ_8WH-ibUdC?VvT zLWk1R)&b{y@_Y_B(zD@bE!agj#6b>r=|EoS$2E1m_pDnmwAeM z$ZPtED=Mz@!@YPo$f4b2@v!BDj5&FT8lWCHcr62maH-RR! zzGJR7O2VF{egqE5Lp{-aY5Iu*Ec9c}r<7)6)b7)^snpLQ;G9oC4+3Xe{YYCq4jfVU z-nbf1Mx*$dQ&#oar66!(hPtCTTMwKGgrZ)gZR653(L{6ro(bn>;Ecnx49|7|kWQ51 z+Ca$ICjhBK#SO@VfE+>&amv@*LdZ;Q@d8>5k36!jchVM}C@0ziAE?Q>G(YwL;G!*D zIT&bDX{!$-2ZBPLDaKqmejTEGj#G;Nq$%UlY?bsZ+Dnau_VQC(gBq4*hvR4hGSex2 zlsMj#MUj6#J3OK3d8(P7w4XD&JUHkR_LFTpB-cNo(n22Bl=2V`&5KWSnO(BhKLTVJ zsu0>Bi!!<$Nv*0w-D&_|?LwS#^9AG<#yWKfBJ2&&iDJ+Y7G>4XKLE$vtnb7&Xsi^r zLG5L}G~0LrU|}26k8#fc2ZBOB75JYs#&JL9_bABWHO*PA1I&c4^ViqSgd=Ti95_O& zL@}rCoR?>3Cvps4NMv1tm&dJZp39SkfT)ybXA9yp)A74E%!C7zs@S=6C($6Sh`9|S zS(kRcEP2aPGI@VeH3tWFNwl*9Ak{*rN~xE2J`h!G*+s$ z*A(0}jX^xAG17_o(loXRI6`An%*UiQt^$tG27i!Y@~BgPxt3ui0s1ikiyVSAnjLDQrxR_%2-=)c4327?(DhZ`ZXUzH*D7z2i4w zx-!@esOi`eQPZhB5>e~}PN~#}u!9c*Lch`^p7{*jjedU|uhbz_>chY}fo2jqB*+7R zxJ)?z0LWpG6c$c3g}Cz4W+$%zXM6@6t#=Cvsdds&YlTLJhwr3ybP4&#QB7o+cD8ya zgcCAP?WGo=mO`r}Pd|u|rpy=dDb`z=?AdzJDtv?9%2U|9w3c$6PNjv2)^|KQo$0OR z{lF1@XDBh0n0oGa$SGQBDrMi)5ETSjS%?-$_h>l4*qT=}wDr3S~3ATGS}X4u&Orcx%zGk{dX zc^Wvc01`Dpeh0`26J!o-*@f4}j8YYVjO!4qR%!ngO_gEwW+iJnLN*oNA z!1*-(TdzAL4y{E*TbSu+dVWsVv+;(OMop{xVZH8JjuHN6)}7jvT2i#>4`CQqk3(%r zb7aw`>&%TM#UdS&=7bJih*{C7-Kn)jyZf~KDY)RsNxmrFqIOJ}DaYn?Q&HDmvh z`?PvnFirDgs0Hu2#vZKJPgzwzZJAYERfo<&{R4Z90?}$5{LusPC&ST;Ju!Z|B3-|F^ao=F!zRAMrOngX7(jc6?Otx-eh%(YQkFI!ws0@BaCgj#`yvbXH!a+|E!_Wz zDU-SGbQZ`vuY0M5`)d~Nw2m`rWBr>J?&Y)MUTon`Zz-90)wWx>XDr-Zv*KQ0;r_gZ zJMC1Mf6BtWdRE-e8rCbv_itFZue5M~(87Jgthm2v z;r_6NdxeGjeHQL@v*Lc*!u=r&_azqYcUZV9v*MnyaKGQez1YG%{GY`A6$|%!E!+z% z+;>^Hx6G>UCoJ6Wws1cO|843Q>pcc{xfe&D#1wPv0By!;pRm{WD?X07dMB3)a{!S7qI) zy+qxK$O`k~9FWh0{IIP1R68Ep!2r65rN98!tALDYbU0)#cxe!PeOZpVf)~{b z$T@3IO^1hMPCnnq7W6qu{IjlQrqGYn;fc4Q!&+U3*!tkRdm1NWNAUq&hxjR|D$g&_ ztp|rnqo#*uupgp$9cdnog^7x6Q^U}xhMIl^9m1his)2)qK07^(IF-qLpN->48|wr= zbRXal)O=|>ff-#tQ>+=~UW#AW&-6A%-dNZe*AG9vAxk|h0$C29M?d?3Q~EaaBk0Vm zpK(<8KSMvSy$${BcpLhe(Dh^8YwF|QmBpLPkXiV#o*>}dd4yS2T zxpJA%>yAjyrS+W|Z9|OjYiJLIbLab7WVOa6*Z8%D%-X7d2AOs1)g{#XvM!IddvMh` zi|2pB(1x62*P?aIp8p$$=g-yHJL3MDg*$lw6R+Au7Vh*8l*Ey~_d`&d=oi*@*ZTX! ze_xx{KB37x)tDmZb?w?pYI>ZjJg6qGDfdx^T~N$YuXm*RXDphhuV|Y!{~EZMAnR)l z&C7OwLDT9x;(px1Jz?SgiiJD9!y)C7+)vDk`x6%KVGH*cE!+z&+%vP{K5pUOZQ=gB zh5K1}Y;)aD&x$*J^4Qd->vmbVKV#uezXvgMKRYY#M=adiE!>~5aDUOloh`{-Q@V# z_wreBf6&66W`ibqY9Fw0-*4gWnicm4EZkRGxZiK#-ecijIV-(_%@tBFxSrdv&Dt4M>6wu;Q+C1VW1~XIM#1XtrUa_XNzBrC#r7E#rXNO}=H_i<&&Tr}gLB;d(lgM3$18e^}Q%zM`T1 z@)y6@*7kQkLHk;Gd63=_nsTq{ztQSQe}AXTL;EDCPR<@0;d~W1r%`vxo$4JpsEm~GTY%I-T}Hi5a-2GRtA}u)jj$S^lV`=REd;OM0!JIo1tbp} zpW56;KrRME`#q6>)Bs}WP&+x+#aDkWDUTO8r6xUh145UOhhqB)Qko6<1R!FcO`~%N zkSD;_(AZZv9ak2e;#1Nvkl5&K(zf;fpZ%m&zS0U420c= z=quhH(YW^lN1G!-hxEge#&-QTeL|jFfurq{2*{m)XnPj|@<~AGGUWLJAa^6vkmo2M zh8+_2D}a=mdea|>j>*O@z)N%5%v12X91vR78f|(tAle%p0>=x;CKLBAK(w7Mfpaq; zr6wH?1F{1G7?yAkAWKYiz6?mE3Fqs8w8*^_L3sj@(`w9cmh(PoT- z@>c*EMk#~Ww*iUjG84rg0>W5b7O#_3%4Dm*2c+E8%Ja~|=2pH85D$QYmv&Y)GihTZ za83ZnX!m-8m^8l&kUHQPb{GLfn;#N&#%=*bd-F;_?gYfJOzj|R@wShP%f#5tAg2ML5~9>=fM{<+3CQmODK(8vbMVWCdy#3h z*Cq4`5L^ai9U#MSHKOhqLHcPttp<+4-A$!*pFrgUfM{!T!979{=C=44AQL7F|9e1c z0Wm0l6A+Tnu+?t^QfZR;Bp`Gd{q!6l6()Hu#urI9nJ8ZYi1y~5kgygIx+o-Zg9UF5N&Tq(0K@uI#d686cF)lhNjhHfNU^X!pneY@0bZXuL0sW z)#49?0|5-~rHgPd9MBCN((gQsIRKDZ6(G->aIOI)tV8&$2{zvXTv2zGrUc{<(W8u6 z!A_L&>!pbDen3u`^z(5*UNhnR4It(jjMRH_@0 zapW6qx*w1eND7GdMTHY4${z<#xnB34y*S4;gi@y2;Aep20TH7Yd0Nztgd;L zKA(o~;qN5#5>Y14u!n~ zXF|t0gH%;_s4Lm425p4DVM(LNWk#n}2XG#1R{$rmsJXd9;y^U2@-OiZ1R}ug zMmiT!`p}%3;Hbc+tvHd5P65MtBp&aU4xF>ckA`X$dIIICG^M!{%xmyrKhaQTCE@rO z?F&(8kpz9E3ro2+LQh(yQ}K1HejG8&$tCGD*x+tU6>^b)40na^QL90IT6=Eg)NZs5 zt-+}VIIuJv?!xizRMbP%x_h*w>0D&Liia*NDIrbLuNLi>87Grog3%uobr- z1L*brk;WWl$?qrbW#`diZzQRr4j~-1Js8n`v}|D`f1)HmWm4~U%a{)_RmJDrjPqDT z-x9!X8~`MbaFJb3DBzY`Zb7l`LA5tL*o7mpyXm9eCJ6t`w?z!oaSEi=e)QH`Lfvd& zpBly|#rFuq%Q|3OG^03WobPm3WM#_J$EShg=ubLxVjzT5Q&rTDJ_V)r#(M(&VI1Sc zwzjGDIPEAjlxPhF2V>m?@M?;j0@Nao;^x(qHb&K^T4$M@rOI+I1KlAEUCI)|`eK28 z^lz0mzSyqDa8w39_m1M|h5@SAUi2~2e$~cxHCNSI z>ZP`J;Iy1ZoHp0y?eNfXPyXh5aV7>Gpl0z}>I?;dOzlvWjD-7lhr;{h7xl8z{LMxq zt!byttEjxDy5Va%+-^eJo3K4-Nr5x@zUA&Afiia$zf^(PQq>RN`uHrZrRsF1Ffdit)Ya(YZ#2V zySwqN7wQhenvKkQI(H?9l6NQs!GP1^)um#pFWxj5ArlRBg+snbeG+HeL=qf9ryGhS z2QVJ;-izO(#&FyX28DrlI%UY2XV9d|H^CK5AePs^K{*?6(p+B^BU6$lP=ha&<}tfwr)562UEW>>F@;g$DGIYMjQQcsFr zsVBwJ4(r#gTe}WCXYB7Z!-1J)AL`Ot;hi={JH}r=wWt37- z4;v&Ua}ANIg_gjKrWd@@+{=k+q&oFPMO6)JM{WIqcmm!X-j%Ap4`-tdw8QJV<6s@4 zm^3@`UYL#=Gf0eI2{jt$-dQq7n@=@^)u*On50++_fgq{{*U%3~L)zl!Vh{FE9fG@Q zlpMfRi88cbS!lJ^?Z;e#KJgTTW1=Dhfe#Ggg!yDwoYzL(gO4B4M1;2rbtpVQ(sU(s z=?R4~Gp|Rd?}v_cza#WKb8paUY(ADrw(NDu5DvmZ^Kh>HI#;7mmaWTX4GhG4F?+(Q zz$hnnYH~{Pkq}=%7teQig{bm;%>jd=Ihq=d)(>?1`6@-Wj6Sv-)TSRbxi&dL%dAvL z3zLx!vb_%{!gu?+r#1n@YK#&su|XVm9!HV(a2#Na1IZ9;$HW3XDiM;|s1jZj&^0HO zq}HqPXeij<(;qZE-%Q!AZoHc;Sr2JqHE2x zte{rpYfK^DG;E|%pkfJ3b!4~F*GyV#M|0}x4+Zv2VVa_yqtq**qAAp&Nh%NtPg~jP zP1oKZ+${!14Oz1vOLH3t(_4$sF)hN>XgH9-nsq?8;i%kgHd7r;km0 zg26ESE++XxnbKDVCD9qHnmfMn)w-y_)J7u~;aFco@SK%C{3jOiS|<$ZosgR|9a@V# zX{FNR8U9PtnQ6I5$Wu5oeFiZQ-$SDUI)X8UFs(%mE6!fb8T$uecm04M8m*Pu^63y5$VLBb3wCNP9l`EU_53^nUZoJlj@hDnvx($VyRd=MdEw zQ-&#=5~>R+_$aGVk2TL5vQ9PoRh*>lCX@(ju1ko|A`t>OrA2YM(Ut+eC$kLTD7lRASp5VaGCei!% zVay%e-H-jy?ClZan>{sv12K0!Q9H9#R7iVFEozuE?4pa48xTHgW|PmE#c@55Ibb{* zFwcsqhl)K~^M0dHUDh0S>aLvKcGP9%CM&l+&P>z3B?#X)TYO}Fk;_V8^99M!1+)>y$UXtmXSFfj{RTApi-#- literal 0 HcmV?d00001 diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/CMakeCXXCompilerId.cpp new file mode 100644 index 0000000..0c63d62 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/CMakeCXXCompilerId.cpp @@ -0,0 +1,680 @@ +/* This source file must have a .cpp extension so that all C++ compilers + recognize the extension without flags. Borland does not know .cxx for + example. */ +#ifndef __cplusplus +# error "A C compiler has been selected for C++." +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__COMO__) +# define COMPILER_ID "Comeau" + /* __COMO_VERSION__ = VRR */ +# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) +# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) + +#elif defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# if defined(__GNUC__) +# define SIMULATE_ID "GNU" +# endif + /* __INTEL_COMPILER = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +# elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_CC) +# define COMPILER_ID "SunPro" +# if __SUNPRO_CC >= 0x5100 + /* __SUNPRO_CC = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# endif + +#elif defined(__HP_aCC) +# define COMPILER_ID "HP" + /* __HP_aCC = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) + +#elif defined(__DECCXX) +# define COMPILER_ID "Compaq" + /* __DECCXX_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__ibmxl__) && defined(__clang__) +# define COMPILER_ID "XLClang" +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) + + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800 +# define COMPILER_ID "XL" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 +# define COMPILER_ID "VisualAge" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) +# define COMPILER_ID "Fujitsu" + +#elif defined(__ghs__) +# define COMPILER_ID "GHS" +/* __GHS_VERSION_NUMBER = VVVVRP */ +# ifdef __GHS_VERSION_NUMBER +# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) +# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) +# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) +# endif + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__ARMCC_VERSION) && !defined(__clang__) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) +# define COMPILER_ID "ARMClang" + # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) +# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) +# define COMPILER_ID "GNU" +# if defined(__GNUC__) +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# else +# define COMPILER_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) && defined(__ICCARM__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__)) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) +# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) +# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(_CRAYC) || defined(__cray__) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#elif defined(__INTEGRITY) +# if defined(INT_178B) +# define PLATFORM_ID "Integrity178" + +# else /* regular Integrity */ +# define PLATFORM_ID "Integrity" +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCRX__) +# define ARCHITECTURE_ID "RX" + +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + +# elif defined(__ICCRISCV__) +# define ARCHITECTURE_ID "RISCV" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__ICCV850__) +# define ARCHITECTURE_ID "V850" + +# elif defined(__ICC8051__) +# define ARCHITECTURE_ID "8051" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__ghs__) +# if defined(__PPC64__) +# define ARCHITECTURE_ID "PPC64" + +# elif defined(__ppc__) +# define ARCHITECTURE_ID "PPC" + +# elif defined(__ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__x86_64__) +# define ARCHITECTURE_ID "x64" + +# elif defined(__i386__) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L +# if defined(__INTEL_CXX11_MODE__) +# if defined(__cpp_aggregate_nsdmi) +# define CXX_STD 201402L +# else +# define CXX_STD 201103L +# endif +# else +# define CXX_STD 199711L +# endif +#elif defined(_MSC_VER) && defined(_MSVC_LANG) +# define CXX_STD _MSVC_LANG +#else +# define CXX_STD __cplusplus +#endif + +const char* info_language_dialect_default = "INFO" ":" "dialect_default[" +#if CXX_STD > 201703L + "20" +#elif CXX_STD >= 201703L + "17" +#elif CXX_STD >= 201402L + "14" +#elif CXX_STD >= 201103L + "11" +#else + "98" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(_CRAYC) || defined(__cray__) + require += info_cray[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe new file mode 100644 index 0000000000000000000000000000000000000000..d786dda1d8f7daee9a8bc679bb5b020542a67968 GIT binary patch literal 54048 zcmeHw3w&I~b@!~Kl~=apm5pTt*kN&Gkcllzwrp&$6Rou?@8Z=1J!}IeSF6=ZR=kpy zefUA#L?9coU6d#Zd6UK^d?{_|7q=zEq=d?tV5g8oJerV%BqpI`T@zvmAr5iT_doNv zckfqgzUMO zeq%0spy)f79kB(zb6NY&zPKwI8|;k*`(2^nz`$U_)fINdk^`>30hgz_&DB5H9j+=V znOz}Cw|E)rzTL^LAN^7%+sW9+AjlbZ1)GzX_b&D>Ag#kao3WD%5SCJ*I{GK#c|vYV z+8GjbxojNxLywKu3jhulWhu&u=s^}l;0-a>GD}4H{}#rgl5`ey%IL{D#wsVteezbu zMj_f%S5+dsH-XH`#rQ`eQr)RhvaU|n(pl9VOauWtL-1k;m*1^UROL$prIoC zi)LkJMTc1DSXG~($8|k~Ob2eNPu2x`V^#I7?F52pK!Lc4FWE%aRmbYasuB^-x0K+A za1-9uxU(+8TUjdrEfgHaO?Vq9VO-GPrj<48Ilyr#f-&4K-0#Jmb=9%bO)FQ|aEPDu zauPSudq3{1i{sU<;gBVie+D4_;K$DEgX80)EWUV4CI_=aDu^rh|p1~t_@eVkFPkbDVAJ#i{KaesE= zW2-^x)^&|HB(|f_t;kB1eOY5H%?^$w);vU2$^7HR_;>jwM7HcwV5H}#N;7L=ohUJ} zim~B!w!{rJW4__XDj^$th$P5-2!&36+j(gn^M!mHe6|y}t|P~h{G9XazVe=1e?P~T zSWiJ-@{ZvnRFS#P+i#hem`H!*ED|+OAN;oSQ;(k735ai`m5mW{DlcxPlvkZ+Oh+e6V!rP1lEBa;HwX zhtJrC-dy5#dQO~vv4^+Rfv1!6PG4-;Gf+P~M;1fg8DGlY2Y#OPEVOZA;TxWc9kwHo zojDJ_ivKD5=|#}TVmq|p841}MLofP|zL+0Ky^#6*h0w&0(Ht-AplW^VLt94bCu)8i z7+L-;RENp-^ree0&1?gzZzO8-rC!a15cj9R*RvRPUT~=|b<{U}%#o=l`1+qDzkBV7 zXX#nragZRgD~3Tm^M=rNGa4Cs+zC*+Bt~qZ`c!EkZSUZTvaN)iLKjJwT!U!Jz8?Q! zCI^mzSi0=plzKWjCv!QNrR|H5^xgUx+1ZWn*KTs}aNl&y`E^f4=P5f3UFZ+yu?$?l zN!?DEz`>uQ-5w%0nEB;G9hdHsL(@Js_Zi-I0IlTZnz@wn?`<1Y}Lg8sjo<|}x2ui0ui2T&iOg-YGMte&CMCLCXQf4;z zWxjT9Vq%m!7CDVNt3UfK@qk=F{Si224o-)k`DGatg)VW|nDfE0-#y34j*1I5P9xi? zXSr*rW5*<11s%TBzd^?8RAZ?x)lr^V4sOT2=ZG_^`WNtHX>Y0Tvp(Cn^Fii(WX$G0 z2lz)PgA2rwvV9nioevh2>e$iAvCl!y>YH)|lKS$Zi0rqEC&tnDY6&pX;_#*G9KKZ9 zQcA)-{6f^#&^J629}!C8D~Q6p;WsBzK5a%}-q5 z8$Rvut^ZB(w@}rGpe3Sse1wx(|>R9OWQwx zJr7aG2MJ2~7BkQC{~ zcU+HPq~kewW?$-u6J<9Nm|XjpQDtPD^rw#cQ_qnW){z!aeh13?QtcJh$jfzg;Y8W9NM&}-Ckozj=x2D= z{APaQ!h=sIE;z!uQ>WMcOXi7UEMj!{sIp)CC$FTrMP8!tIG<7tznPb~VE9d2qE1J? z@%_C07yI`R`!$;=SpU<+&wS~88t?MZZ{WBAO8zRlOy>G*jvxXnH`*)LJ|RENjSiB& zKy>+Q&e8)FLud<9JvTnC{nwoH&?fl5qhcNYdn)QC#>u^H7rnxu?@N`C&p*{ZkA|Q+ z#_PM+xhzpp=UleGqQ&D}1_wX9zR-EcQ{a+Dhb;@BC48ZR+u(#IPWna`mtTQ&`ew&# z9%rfB1&Q{RhAbbrflIl*}he(Jh^oU|cii ztmLdK!5TvEMrf7XJ|GQ~S}ze112wcsR$t?v^d z6E|@4A08{mcvb3K|4eK_0DjYpJ79YhY3FSzD0ld%4Kt0(^{*y>i0+qh!!FRq{?ud6 z1FeG4gCOJ^seRCQ^rd{C?Mxum={k;rFn8+&`Ws4vtyw1S^w8=!-N5eoI zDcOZqOFfz?hLxnfEH#nJPkT0=OL?w2cPa|Bnm10JzzC6=z=UMuTRnikb!t1{P{6I+ ztChUAlr+>{fr+lCx;%5t$;mzps4w-S%mYY{qUUwEx4E~{q?+c`!!NJ%joe=`1X0tA zSAopIA1CJdM#4u>bDI6Q-|yCLI(FQC0kX(tWaiERwa@xS3Wjih>s;9uJ=QoXXzvMVQTg=D&!;d@C zO$F{F1;jG-X1XwtdLv*vm2XRV@5{UwbEL-gFC~ANwr>OTnl~WjUvzWre{=zu(EQ5o zMh=Y4lV&vKo$E`tl=@S@_oaOftPO^b!Db(?yk_x*z}o-Rsh^?|z>k(1*MUHKs{<3r z#p$iZz$%7*QICV`D5If(ns|l4fg^PuTnQDTHh)en0%ZR`Lt^YHQB{-oq24jysUeyK z+Hc9aPKTJ%VqE;Ine$$a$<8eM{W`rE?0Sg~) zQeU8=?*#(-!0~sZn#aBOfj`US!KeWHAYhp{;3~ujN8?-Cw(;ZGbl4NxID#Pl!Hv)g z25~#+Iq!G^WjCS*L(T)QQ`Am*2Wh@v^YlY7UzT}cHZ=gP?Wje#zu15X&zu<7m)61` zZ@i1s{u&DIxoYDlc;arN`$hW1c=nv?)$BI3v-h#BRIJM>Vd>`EJ zS>Nz+hi_RXRevtE1&Oy@iB+@;O%`$)lHc+jd?WQ5*7{r>&>zIT9{l~O4E%N{2GVV$ zK4N+LMUs!4C|vx!bRLGq)X`gCK(_1F-`Ce~M*pQAE=+Z&FxCCiR1YJ=c?Y*oVX9vu zOfuEvrOHgNM!N|!y-u3xK_^Ah_WRnnu+9UtuZ58mW0mVh-^59hC)-}Pb9+rR2wQzz z+3E|_F5Lcq2Ck&}zm@iS1j5sL#C4-?UvF$Gfa{`-o~%q^(64ZVb{_lyGL=yu)M@{t zpzSJMA#D0dZqv?#??L|Qdz3vZAvY*Ox%T>QWNP^sLdhr8fmKZ))`_e0x)5cbMNt6cyu};+MAH0F;_H4vwY10~=4y!Ip`{KlY7s=vr(9ZWMOx zOC3vWOp%Zqh;VAJW1_5(3u>Q3fRU044qyBqWJ;-eOiETFJB#Kc(8a{*&yRBZPTPM1 zJg|Nu>E!;A8^{p25~&{|Z=&q4#0uwrA_$YZI9o8?ran53o^>oSS0EYgk(2qwmUw}(Hm4Nc)co%YGKlfk%Q_idDwlSnftBlv7KCmWt8A|`n#kh!(aPEdFR*N3os3{l{>%gFGQ7=4WGhF zr#KZD37n|(r0a_P>&FABqkA0WCD%W-hqeSO1M5#De?gS9)(2wR=)&SU^YMIA;#tR@ zUD%;{U=eL?U)^{^@+M#Esf-sDK&7wqg|3D8PYL!rh`k$osfqP`XQW`rH?sd& zs$?ETql48Jf2eK)L<%fB>bH%#onLP$#J{=)2cPzjcvyMjJ;VPFO)U5XG%;S;GfKJ$ ztUroA9`kYB0#2?lF+9ix(SAlCFF~^e{^Ilv;lK4 zPidh-!2DClpG0{>{#KGdPn2r#V@E$=JDS^qRk8)KCO%PVwD%izSGeF~u=;oUsAgzJ zADS^Er!|}(^J2*!3PUdrZ9~HIa{Y938amoHEZ+^q?xH=QDxyV%o2Rbk{WA;7)xz zxjg`L`UgyCVGjX+s2=)!E|x*&Zm)(FX2=}pC;_#7TheE8oG z2VX9xzc0f_Wca^j_-Ps5F2mh2 z+$zHc9;)``{yOzU2Ez}-%w=SO-*@!q1=wkUUNEZAdhCadjOp_a8aVE-KTaU7H01Y{ zLtW`9(i2Nx*-CONeiKU{VuR_{Rm?yp1NediLRO{1xQ)sscSMu z0zjGu&~;{c9cUYufYM&>|JxVVROYL$j;C8?*ek=h3|%WkzABWfCrYb43QY;5^RhE3 zKL@|%J#{9Gs7w#Za5N|XP)=HH_A4Uak-O+n1~zY#z+f!2^F|r(?h8i3 zp@h~Q?g=I%i5qKba~Mk@>XLOl))^I{1na@c^2y;k!Xc6Gkl{H=uWs}_b_XLHk$?l)|J=mHH-9iOu^izB z+yUG>a7S>X{d@PU*t52lUII(>^@m+O!M;c`7QR||9(Q*)B#OJ1MqN9Dao510tFJ%U z8(tBIalq1;%eA#HmPiI8*CoTTeY`MahiSQ%cDuUvCBku6FyRX7RAjRm0SmrRrhE-oa`Qi@*;zwAn~Rb*%E`H!H7$mJy=#Le>q*buD%4? z@s@BlzLHD5Z>7@F>N*wW;ZRPR<@npE*NmT=9+Q6BAZo_H`!;j>v7GetIqACHX8gVT z%;{)On&tGX(wua8PP#fL-BN9)U!B9>wZxo1evvtSQuc2quhN|Ibx||^*&O`WbJAyW z(wpn+uXa`LUAI0z zs^BD*RR4oQ%*}1MStnj2LwFgU_7xyrjc_0CV#J3Keq{k;3lKky@M+wYh|@cnd6tb@hHN- z$NfCwV+fzb{UYMy6vv_}Lve)9;ATP4LHHu>0>sZCd>yv~adrt~-@&519Px34=}Vy# z#77ZUUxs=kPT`^@&=2A+gtICb+m3iC!dq~6B0hw00(TT~wiNZlJ%l)gw_MKHM+gVu zU*H}kIKqFxeHY?m2n()&t`ILp_(j}z6Ar=!mCy^~E`;yLeHighgx|w`1o3f%voNxZ zAzq5`FL9qh{4m0;S0W$rmiI6=i2FIjqX_rnK8g4c!Zhv|5g$eP1>70L4Tv4tNgWTkuUY|hRCR`~Nt_z?dt z2`8SP$l_T(`(Sx~X;*ReoX*+NqOn=y_LKQ%Y%O}d2!B-;zCDlGSJ|p<4m)#fDyYuy z%!_habJGe>g{saJ&MIKDR`FU!bw1f`wJA$?x$w#8N!keXYr~KpW#hM_EpJ7;Wx+gm zz%Sos;AF>k42x7khIh*FkPIJ`;gd3aUWTv8&~ZSNFPCAh3P$Bj>_r7sk>Oq$-Y&yW%kVxKJ}kq>W%#TNe=5U_3}2Vw zTQV$!e(5TeVYv*K$nZ)T*2?g`GW5x?Rfaoc*ds$hm9amyhtS0Tl=djGdBTx!B3zGE zAy#yeHo2y$v3aoqi{*k@dEVx5qCOdmVS$EaO9<;Cc99k4?`Dg$pzS+j;b1p_tc#$5 zU_9ZaMJnc6lx|C4g_(@{2YLqG>@`XjlCp)@hh4 zMSPs??LM8YG%)JB)3=Zx}MinxY72AiI1?9-aV8_6oz5&#@-rg2YbPVha z4s=Jt-QK;SaFkYVs1@|fuCupA!r>_Ew6}+2{e1($L|CbnCG72yII6rg7)gfNZT2aN zuzT&2Daz7H5_3-l;nk&|qi9;a7LSHQv~t&kG|+!5;Jx7l?HdGRy>ZrtbRV=D9@x#= zDL&Yx^*|$d9UG}gXmDUR&!>r}rp3bvEf|eziG9&9=C1;hjH4!EWzJZfX~9r`cVvKl z5V8JvuNL0h2l+;r780@lU|J9T;)<~?HclF9>1UxlZE%1i%qj?W4aO4e;sTf_*1e2f zQ6NfQUCLwMsv{b+kFPuDI?Y|u^pFDq3qJIMZNdteUDt}9F6^6j z<3YiSNMBcPCP(xeO1+2X3ImDzvsSZF1XSMZJ1m7=5!R#k;q{na}# zg`Ep}j0GUivxCn0_HT%Q1rZGQ^6gUih`S7T*`w z@cby!7l$hDzx*QP3E%*rEbs3sNZ{FuFy_Z0mUoej)69nMW_gQk7wkuAyW=+gpE&6l zdr%N4m)RD6iD&*V{{NF%D41;b#qc00?+QUi72Ts}EEk1UMzpsdjl}X++2#{N1>U3J zSJ}#li-Hfv)w52Px50MN<@qG(m$C#HjN|bU%X5o7RSfGF4sNi3`-2~VwdZZIX7mkE zMvKTO#EicyvJ20dSpJ#|i6L4EPtB6_2vQ4S1=Sa31%I|+BjpT6u?p;E_IJ-E?NO4J zPxhK(Y6MDBo7mUtNkEwWYM!(^N`RC98`P^%>kjUV^!4t9MclHG7uCAsiLSn2oE3iX z!dr=!M$hnvW40=C zv8|lSjK=!5Ymv>!0R-1xO+%e6s<6 zr1V+9=VAc_Co~wf`6eU81`Oc;i!hEv^{-$wHl3{ zaI(B?SgnBNXT#PBSb;M#2v)L`ou^o#GdU0&j9_`JQ7)V1+|B)|NI9Gl>=$t9idcR% z0OG8jV_i6`RhBetTK96y;u z;&gYjqF*&^W}E6VUh!Tk8nz8(w~aQQ{2ILIME7~bIBivFDgi|6;_sk>Of7o9G7 z4Kzyy2+xCA(XTjC#r*ER-5B;*(JLIIa(@5d?l_ckW)@X@10`=k@>QO!n~ygNdc&X@ zhh|>m6g-3y)}YzGL00q|4)gJ1T@kct5S92X2L|TDL?z^nl3B%gp2Hz=45r}!dk)$$ zzbC2@L00q!UTP-+1etRjBSHXK<}D7{yP&^+uPnrDywm{>62)w`l0{(l5e||C^95{l z!QTFUS<)^_es;mWEYO9d{ks?3qJs);g#Q@CW%3)8&-?XT~s1ue4R>CowM_tBJb>iUcMaz6`@5!tf*AL z&y`7dG#t~y5g0(JZ4tLETUi|M7r=SwMdphl1xAiuXufSR6>`|hA~jkl7}^<@HoriW zDMrRBQ%0G{D7BT56A33mJGCzC)$C$L3q{TXu<0XH4Gx3{lX32A2rV3EMHdQ`a$8v! z-d90U>Lje_A^~1xE9>FC|&8#j&x`z((e-K zYNX>gWBaM-QUR!iXlMd>siGwUvd&fpj@Sn+dba>Vh5>-Acrzpc^T zUhmUHfkFeJp#w72H@0Z*CXcqM)!hW7)vGW*>q1Y4v9^{urpIV&CL!BcQ4X3r(2>Q8 z%{H>#_4OT%9RYW{S8MKQ-`wnP+N`--L1K=9)6&`;Xx`l6)jHZJ8@2VaVk6tz;pH-N2P2-Mi@@i$!0E;7KREPqqI$6L=X zHlY5dcJF3ytLAAy2`_JeHg<`T-`vu!xi@#PMFz;dwb}0>y=x84t(x28X=RIz+%~*_ zsQJnb^?`N|t1!bhwX>xLLfPS1t*c(W?kZvhAJNp_#+Dn|n_*3@!n3t$ZKMfwv;bRSU=XmQ zNoh3D43mN>_#0t=Ra0TLwKv0R71~NOT8q1W3))7uAk|&RtTtn|U*F;lc-tTt(Q9Kh z=4_IsTHAEJ*0R01m8~)|$&_0mH2f@CK%3UytZjw0ubu{_p|!b@Bh^ldMD65lZ9|uC zV`~fy;ml2@+R(xq)!Pb1uQf2KO(6p+qGe-TH7SPR1_JAhY~Gz(+I$@io7j2-ENrlL z)Aew!eC{?p+T|=W=tM}nm<2JS-JA3=8HEXA8_KnjZ znp^(8CQPu?Tl#&b9Ac)drOwEaUUr+m-ACSqxs5D$V4M5;Hmw1p8pc4>PlJiGO$LJK zan$((-X>OWWVHGG4ed3|V?b{3l55!Bj$vIByqY}BYvjXoG&V!MvP+UnV+}@jgBu-O zsGe;$z*){$+t%uD_u`jf`pC;2Q)7*`)$i6|yM805shPY*i`(Do#&E>0HFDGxfhHkh zu-}rEDP_El`vw-U=J@<#($Q#S$qJGBSd#%3MjdFD!*CmGHuA`vw%7YMZ(=QGAZk?2 zt}|d%4`J`*$5^Y8BWzFh1q?!z-DYIVnFg zjVv!lR&6UabVo}Iy23UiD}d%>+nM7r%uD|qGeJJv+$Lv|e8$)l4$>P0n5%!uwvZ-^ zVm3)z(7Ch8C3%H4cwv-Ncei4~MFW>P-9qYZ))4- zZjsYL4&Y+r)h`m;4VH2`EhfNRG(+s=c?(IZ*?U1h)VlF{gocOz zS_04FHN2P~)&zckPZ;l6u%hepO8ycw?2bM7zc3c=)k4_W(WlW@+6(W)8?Mf#W?^N_ ziFpfE(?da?vz~%{=OzjYoNayz?M@F53!NBK0BFP9v_8%M_zJ{(~n8{c9AG{2E3cya11=F#F;(FVS)(%+uqzlnV1$L(FPkt z*Qa!;6Tg~p%jx+%Cyjj#{#NvF%A7B1x1EoZob&}8gGU!Qy<5SbO7L`VO4IJv;nHeEM^s!R|cfX>vIP%FD}Z0wPC$>{iasGXR{ZJC`2(1$aM??;z+0LEuzdqLddEP(n1vCFm1lvrtiviN3!~A~;BKs`#v;c6Zt{S44c0X|pjBAc`DoBn)*qi+Dew8QfN3)XCb`y}!YQ@W3ug&T>=2)&;`-A?JnGA*pZ-O{dtKr| zUtXyWP|pBeI>hvlu(UvHpl5@ewt-^+9e)i8uEFzS?tLa${(BI|)34}YG(@i$VlS$T z%{gaVNH~CpBDV-oULFS((3^1@J&7y6vUENkxH)zK@ebUj^rVZ=)B}FFevK8coVOov zKs_{nSI}w>EvF(S>x*U=<*VOPm4A^yR}-jwMID|T{C|Ae=CRVkdA9ks{JEFRT{`yy zdXQq9XItvHU{1c{5=SY!f64y>N1n!(N+Z7iHv|>AFRB}1QnOk7X zcf5BFu@F3oj+0-HZb}!nB=i9 z602O+^;fS{FK?`*SutM3nCj&Xfw;C-ge&1Bb|t5# zE8h@#8(M>=VhQ~4IbOAsR25HjqpXOF7i&daPO3x#?-ApnJmT<#^n6@E=@~ctr~uPb z!WI0HWN;uswDBO98U`^uil*2Kkf01Cg|w@XfTj0#MOM%|Hk5~?$_p{<<^SpWe_8|d zE*E`+0UdI$t9X{<5Db#89SN~C}^N&vGsvi6T2vXw%MC`2z3E;vH^&y6GdLEo_1IKk9oL>Xy z3`Vx;c+m$XPXb{&oGQXO51jyTs5Ue{5-rBI0dnX(rTT$0dLHidPGvQ2Lx*2MYJ3{X zc#knk5|HMFJp7$Vq-a{ILqbR}mky!SBcM!|QHv9Rj84OguzvxZA>4+9zeTG0Jf$v1 zbJv{*rw%wk$&%+%ybsox}1J0Rg=+IBJ@JSPf7ZtL&(}#jP&qMjUz-c)T z&WpeqIuFj9z=@s*rxZ0f3>?xt&~YsRJ$!BS{0>8LVU1;>(?l%v`St=Xw}G5F{RaN0EAXmju9%Yk}ic-Nhjt@X_a&-w5mLj zfv2=F2$0YQ<$WLZGG7l#tx`rlqkc;HEvoL5=tpTo;E*h#%Go2wX4>!zavxu!jJp{M>#)R)${;@D>|2m8wE1 z-Ntn574i_B@1f)@+{UHai%JRWC95+xzO}u~?Mc*BTO2@Kw1su+MzsaC7g5N!Rp5US zZsSsVP6H(Lj2{-;O+A*5#pHYV4~U;vfeH^ntw4k85)M$nnC^A=!mlkxGZ1 z$a(uRPf{;AUfc~j!Zs$sk>ds7P;S1>+E3}k!iw$w`by+aHC`zD`Fr4q_QKDVY1)>h zANm0}fyPwdF;^QUVb4-O0*B zX{$7+mp&@4#gow}e)yDCedYs!@oDOg;!GnPgp>6hrHMVjIe8wO&jaT$Ov~_We+Nh> zN^xx<#B3RmI#k?%JO#)hv|_`(TQ@RE%3>joJ;w!djS`1 z;mW~4n@U@K067p8@=P)c%kk?F<#U`;{3mT1m$KET021w`4TSgbb6i6TOWEOJ7(AKj zbiVHG*x^Z~=gH=N(tduY%Y&moVL#cnLvp=@N(*^hlgdLlzXi@oF0)J4x&WMqpbDW4 z>c2*}BfV(a-fk_3?|30jx%mQe3uB!+1QB)#=yYPx5Ef6(ImNUk2KNj%#ki%=5vwkOv!q)}r>!!nzHZ}$vp;e-o zQ+LkGb3-R`3|>fNU4oZ~PO~`=PT+=?^W(VJO@{-Ms<`2X8%P$?ikRCVl69#QX9+YV zj)lj(dK~`^ z)#t}?lh>J&j?~Y^x_@DDRA2L@dgb!~lb~W&nS&#HIx&tm3*#y1?Y*G}<7}G2on0IJ!1ODbfZ# zO)+0H)5atGFCR|dX_#Msax zVH=ZqB%=6nY8E^>C;Jh0@K=D)?>4#rVd!r3i{yBv4xv*22%K>=lNcEZ@*O~2CY_kUd+k>w!b|ELwRIo0ry7uG6Ws5K(={qtlt%S~TDY zYuTIFo0xp=H|i9vG?}%$6Fpa>Zlsk-_x)sFPU!Mr?@WDg%P?Nn2LeK#smF_9;LulY z4LkfCAU@pqllFWcqMdNA2IL8a^+xsHWFAilRr!sN=$gkADX}wqgMm|g2J)7|4RW6V z+{v!rkn$h`1=L%B4TdMt%?*eXkReG&RD3xg857R?NK9+a!7}$wh;1=MSTFI zuHYQizjtDpx`Z~LDz1mBEjsnKpt+IxQf)D$w*}#td$`i`XttjFVdYuYt?D&|cilzgmN>aSC6LBw({CC_Jdc?cm+n%A#)BF_*?QF~4*v)WnG<*}H&Ziiph<%wb% z6UtT(m+KBlDD>l+louiWC0PsCAkz9}X?HxQ=XM7ZLC8IX`+Qn$(X|TXoJ(0RS)CYn zd^s4#e!^kk2v4#XICzsX>r&QoOmCeY{4O~QK}H8rQ@SvDKw^-9k8YF9 ztOz|NaY_)+x6#LWz&PttI_$*DyOfh}Q}3}DNXi2Y0rY>PL!$U8DG#QI;6=ULYQgtP z91NGh`2zl1udhlRT8rd!Z)2vT^!$vjXXBkMMNQTHkY0C{V}$>ib*DC^mK1IJBN&F& z<4~K@99gvK8gpYwu}FucIiW)rVpcS2cWQ0X?tf)LQ2I$iZDQUc=KOLA$bIR|^kc1) z@}krBFS$>vw*^z0A4M&=)fs!Rs-Lo|KI+~TSJk0&Q2)Rlqkyalz!R7twGTrFCdk?z z45ktyx!_OlPXP=*LW=4AFy!WVc~vwM%>p~xNop2?$s9V^ekUe7M4(Zw}tzAE!0&TBmYU< zU$k()%fh|D!hMH@d)vDRa7mwR!;C?)3DLE4N{AGO!_D;~yN zy@gBYn)KO?nuiMp_DV{x6B+Sdlo5o52l@m%YD)3pjA`^ydYf8rFLm5Q7^I1 zon(Ji*8Nj@-HAx6d2tTNlOP|Jb)Rg@7u8VdN6;Z0TBRB|gsSv&7;!3-`#u}T zkv7%|e&{~HA*lIMdnp-RKa;E(<&&C#uAixG>}zKI@bet9)WbdlSq_~?KlcEq^lj)z z(3xI8W2o+bhJIdt8~WM)HuUq9t{>}O(@y@SS-jf}nS~$gN$kYOLvf}NN=eTq`_5sm z!ztQSu3X0Tx+9WvslGF+-1G zgR9P2JpW^cHsrdp7Oi9U{0|$RKUZV#i2KVH?)O@_FR*Z@cc7#^()SKQZNhI@+g$>@OJz>eel{;(={6`-0!z=AGL6I z%!oTZJ2!Ku*`Nthd#{E2ehc@~8F9bY!hN}g``s4qJr?feGva>8!o9-6{VoglfQ7qj zM%?eVa9?EMey4?dt%ZB#jJSW+!hL~-`vD90atrtB8F9bM!oAqSeZPgf!@_;tjJS_l zxEENsCoJ4wQL_Slol-X=?srgFAl%N32C=rUkmwUCm@Gw4qh9Hf;G_-kShUEE=mc=9ze>aJOXk%AgbL3HN zyj}!^E~r3q{|z8@P?u4!`Fwkz4qxvf9B3n=1?eo>Y;C*?IBGN(+}{I;n%f9SJs|4$ zL;`XHAchXrS+b>k1>}HbqP|KYO8o*5x`aIHY~3;bEL&;* z72tFN0nSafg#+$w%w!uE5yVuB_W@FeB1Wn0fV?byl;D0dATGU4)fvCy?GeR&6gX;* z1Rc^3OB&l*RLUag+zTAFPa+_P0a1Gw0&)}(x(s=~2gsesH2TiJ17g@AVVBSgadLze zbSem9vat<-sF|n0X$FK=wMLtU08wvr2%G^xHki1l0Z}_$0_XF9l$vz-*MMw?0EQ*} z6CjIBbiNNrr3vRnK2pju}$aMbT6 zM5&trAzP)CfP5GbLuO6GFOTsJO}dQ!^)cX>A@>4O00KtqJPL@KF$&5*0AvWo3|_AT z64hlUiuvTOSzQ*d`G5?WY;_4B4pS@FQYqYqgx4bF0Z{N#r&o)2PF%94UBEdB9HZSM zfQ*|oe-My5;23uJ89>zhkf<~EWkA%MR|0Yv5W_On(bnQ^AI1Hcb<_#t;$1$MOUjR~RYWM#DM7>ca=r|TI7BIJ2 zBR-JXwSYWp!r2B$M2GM>5-hw0xT5YFO#sOIq1TBqm+0(9seoRJAfE-~q)9(t1>|KD z&Nl%u&kvsfMC}{%IY}SQ(9HefdEii0QGMAuuK`lYwW@Sz!!KIeO}t6~IV?*c1J|X1 zxO6@9xiNUrWwdfFa2__%*#Zbv-e~1+K#b9Wa(4ql(g_@mKYvEMo5sNdz$rJ${4qdI zq7+FdB)lJxZWH%M0O{0a1|k~=#ATxM0wBdE+xRsg37rma(-32IC~edfA1J0K&1%zm zfRvkfEdyk~P6x)6W8O5=jA3 z-%mJcqWo3hIP|*r?7=y%VQ9oO_j?F99uP5l!Er#ygbc{f0Xbx{s8<0QmGY9@z{c-a z=rY>~QHx&yLYD#g10WBWTBj5p@T{(RO@5fB6QvBwmB4Ayb%@a+ z5*|R0Gs$xmaE5do;@SYnsNTv1*#$^cuRB3*1*Fy_&*umS@(9}?oPPpD?ckA2j6DNL zr-|3k0ojfmVe`A?6y%Ue!qy;=|l zK=$HL6`AZC=owV;U{_Zxyj!IreK_n_V)ex6WM7$p+UNsNbO<-TLXQ)A`?^~|wLgrL zCw#$y?g)<9#E;N5It~#hq>5i5R#f5CN__RbN|ozNL=y3CoC2=(48}qr&VK+u1=_xW zw}BN;4xSH78bvNMI;}d0^H{rrIEh8e%@q;{qfw22iN8NM0Nie*a}lKv&8Z2F3T)bp z6WQn#Fq}u?@owtCIeYwQs8*pTP@YUv%AH^qgAeu4q+U%Jvg9#qHJL!e~=_Uq*Cv8%a|WAO~c3AjPqDT-x9!X8~`MbaFO5} z0yV3s={1}x9tTIo>6Tk=VfBsp5nlcF?e#e80bhHK`LVwUtHjc8Q0t8hcH!*oZuwBLtreM`8T_3zUn`1bg2VWC+kk&E^g$C2|5@QSQVc})2faGViJ zhg0;2alEPqMbHQH?hi`1)+$MbcjDLKD zY2A>uJFFiRjtQtat?G&Ipm5pvJV3)%&|qv|RTMq8sv4%Zw++8}MKhx^(J+15U5nvN z4SW|K#nE4bRIfegjHLal^=oRbsv@E&Gq8&3_5Ae;@-4r z3ILhfp(;5L>Dv{K?2{kb%S!VX9*wlpPMg=K@tW#AMCEY139A=msV;Qt73xx5vzmqb zlbU#il49b8RBiGeC+Xp*>ZBrVS9qT=cBRX#{7{^!Y%PKVlF)|Q9vq3p8=DB=C}N#} zYG8tggrY6@F|-;SsUoV1XgD5A_kh`--&jFhvG=cSrNI&o)lb9CCX6<^w3ZyEHQ>nH z7OymjoaCl`O*A4arEU%;@G1fp1Y zS;i@jC-Tf=f+ogc-Y?})uDYe36unYUiZdYAu358s4R}u5-)SloC39#Kvj{)N9vZR; zD)uHd^r0^F9{k@Gjtzt(IAb;lMGAYQ7iz@}1D*!FvQO?2ROBp4Bw7=Zt$moS1S1^- zIAf%nwS^NM1HwCW>rTI+FM_$Hl!AKLASsz^h*T}K1ZFf3;g#lIPRuv8$!9d0W>`CF z8wkb|@b2)gRP}v0M6JIaUe_H5>oCQn*^&3cyw#X$V*E;I(Kz?ck~!LZvZ<~E-U@5M9=%Lk*J*wV=<#YaMXDqTGG;T59F^Ti1ail)R`BwF9!9pK9u z*)sarZcv+g)a2Ua1TE87AuUWsI>`2&I6A)D-#xhr7*=DHXo(HtRP;ECv`69qV;o3^ zSvw{c=uwHV%tn>){(!DIsU)pli$}wuzMj62;rXWP-eUYmp9^5#mW(#wBrck4cn1=^ zfs`@r3k}Tq=p(w;OzRJ7MZOpn;!VLu8U-qrz*I+eD}8aLT05Fk*FZS9dlJ(W z?Hr|E2^CGE4kf8TBs{eQ)SIroFSJVxj0#!VkEOW{gsH7X=$KF0qmf_&i`#zPhNE&@ zk~2W>9E_W~B`I(!_k%VH$1Htwx}~KdEcX9{kfG1K#+B|-PJ_`}^}#5ew<_n}C=eHO zQ4N!p-T|7ebLSyfk$AksI~NQ-j%5k=y_gVpvnk#8WNqNbp`W5(i}sL@MyE4k?hm0U zNQ{||vf*}`sOa5JUph+z!Lmr&2p^xaIm!(=v*!}RU`-b0i)wtX7t<+pi|)zBK4^+M zr`bIjl{Ig3pnVO4)5oUWp-=>V7n6LUOzA5_lIXNm%^lzPvR+hRa-$Kebu7doc+Qpp z{3llXsuPCvPRPxfPPav#v{LEu4F9EcW?C*1@+8hopF#A;chjhVj$lk7OlJTZR-C<< zGd3CoSNQ~qiy6WGR+4sey0M0Z1!HB_6HG?PL70YWEN^9P_yE-sj!|C?;?!O44fOej z+$9u@rfqDa;QyCDz}T4sTwJXPf7A zg@~veOev~%6;XXLOPItDp}LTQ53Cw>Qu9zNQufLIU&BQQ5l~3FVF&AJlNH)6Phq}2O&B& zsd;oV+5_+4(Uz)OL-AJ#^yGBYj_FnrlT9+tHIF?6VA#JVtIPgspv32ESbD476xm^vK$KO>M+H~;_u literal 0 HcmV?d00001 diff --git a/cmake-build-debug/CMakeFiles/CMakeOutput.log b/cmake-build-debug/CMakeFiles/CMakeOutput.log new file mode 100644 index 0000000..201400b --- /dev/null +++ b/cmake-build-debug/CMakeFiles/CMakeOutput.log @@ -0,0 +1,498 @@ +The system is: Windows - 10.0.19041 - AMD64 +Compiling the C compiler identification source file "CMakeCCompilerId.c" succeeded. +Compiler: C:/BC/C/mingw64/bin/gcc.exe +Build flags: +Id flags: + +The output was: +0 + + +Compilation of the C compiler identification source "CMakeCCompilerId.c" produced "a.exe" + +The C compiler identification is GNU, found in "D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe" + +Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded. +Compiler: C:/BC/C/mingw64/bin/g++.exe +Build flags: +Id flags: + +The output was: +0 + + +Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "a.exe" + +The CXX compiler identification is GNU, found in "D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe" + +Detecting C compiler ABI info compiled with the following output: +Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp + +Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_0d28b/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_0d28b.dir\build.make CMakeFiles/cmTC_0d28b.dir/build +mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' +Building C object CMakeFiles/cmTC_0d28b.dir/CMakeCCompilerABI.c.obj +C:\BC\C\mingw64\bin\gcc.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -version -o C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s +GNU C17 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include" +#include "..." search starts here: +#include <...> search starts here: + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +End of search list. +GNU C17 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +Compiler executable checksum: 985ce7ae6dd3a696cd146ca9896b0035 +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s +GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30 +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona' +Linking C executable cmTC_0d28b.exe +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_0d28b.dir\link.txt --verbose=1 +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_0d28b.dir/objects.a +C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_0d28b.dir/objects.a @CMakeFiles\cmTC_0d28b.dir\objects1.rsp +C:\BC\C\mingw64\bin\gcc.exe -v -Wl,--whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a -Wl,--no-whole-archive -o cmTC_0d28b.exe -Wl,--out-implib,libcmTC_0d28b.dll.a -Wl,--major-image-version,0,--minor-image-version,0 +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe +COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_0d28b.exe' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccTDRnSd.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_0d28b.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a --no-whole-archive --out-implib libcmTC_0d28b.dll.a --major-image-version 0 --minor-image-version 0 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_0d28b.exe' '-mtune=core2' '-march=nocona' +mingw32-make.exe[1]: Leaving directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' + + + +Parsed C implicit include dir info from above output: rv=done + found start of include info + found start of implicit include info + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + end of search list found + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/include] + implicit include dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include] + + +Parsed C implicit link information from above output: + link line regex: [^( *|.*[/\])(ld\.exe|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\]+-)?ld|collect2)[^/\]*( |$)] + ignore line: [Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_0d28b/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_0d28b.dir\build.make CMakeFiles/cmTC_0d28b.dir/build] + ignore line: [mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp'] + ignore line: [Building C object CMakeFiles/cmTC_0d28b.dir/CMakeCCompilerABI.c.obj] + ignore line: [C:\BC\C\mingw64\bin\gcc.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -version -o C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s] + ignore line: [GNU C17 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include"] + ignore line: [#include "..." search starts here:] + ignore line: [#include <...> search starts here:] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + ignore line: [End of search list.] + ignore line: [GNU C17 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [Compiler executable checksum: 985ce7ae6dd3a696cd146ca9896b0035] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s] + ignore line: [GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona'] + ignore line: [Linking C executable cmTC_0d28b.exe] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_0d28b.dir\link.txt --verbose=1] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_0d28b.dir/objects.a] + ignore line: [C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_0d28b.dir/objects.a @CMakeFiles\cmTC_0d28b.dir\objects1.rsp] + ignore line: [C:\BC\C\mingw64\bin\gcc.exe -v -Wl --whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a -Wl --no-whole-archive -o cmTC_0d28b.exe -Wl --out-implib libcmTC_0d28b.dll.a -Wl --major-image-version 0 --minor-image-version 0 ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe] + ignore line: [COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_0d28b.exe' '-mtune=core2' '-march=nocona'] + link line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccTDRnSd.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_0d28b.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a --no-whole-archive --out-implib libcmTC_0d28b.dll.a --major-image-version 0 --minor-image-version 0 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe] ==> ignore + arg [-plugin] ==> ignore + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll] ==> ignore + arg [-plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] ==> ignore + arg [-plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccTDRnSd.res] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_eh] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [-plugin-opt=-pass-through=-lpthread] ==> ignore + arg [-plugin-opt=-pass-through=-ladvapi32] ==> ignore + arg [-plugin-opt=-pass-through=-lshell32] ==> ignore + arg [-plugin-opt=-pass-through=-luser32] ==> ignore + arg [-plugin-opt=-pass-through=-lkernel32] ==> ignore + arg [-plugin-opt=-pass-through=-liconv] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_eh] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [--sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64] ==> ignore + arg [-m] ==> ignore + arg [i386pep] ==> ignore + arg [-Bdynamic] ==> ignore + arg [-o] ==> ignore + arg [cmTC_0d28b.exe] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o] ==> ignore + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] + arg [--whole-archive] ==> ignore + arg [CMakeFiles\cmTC_0d28b.dir/objects.a] ==> ignore + arg [--no-whole-archive] ==> ignore + arg [--out-implib] ==> ignore + arg [libcmTC_0d28b.dll.a] ==> ignore + arg [--major-image-version] ==> ignore + arg [0] ==> ignore + arg [--minor-image-version] ==> ignore + arg [0] ==> ignore + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc] ==> lib [gcc] + arg [-lgcc_eh] ==> lib [gcc_eh] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [-lpthread] ==> lib [pthread] + arg [-ladvapi32] ==> lib [advapi32] + arg [-lshell32] ==> lib [shell32] + arg [-luser32] ==> lib [user32] + arg [-lkernel32] ==> lib [kernel32] + arg [-liconv] ==> lib [iconv] + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc] ==> lib [gcc] + arg [-lgcc_eh] ==> lib [gcc_eh] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] ==> ignore + remove lib [gcc_eh] + remove lib [msvcrt] + remove lib [gcc_eh] + remove lib [msvcrt] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc] ==> [C:/BC/C/mingw64/lib/gcc] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> [C:/BC/C/mingw64/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> [C:/BC/C/mingw64/lib] + implicit libs: [mingw32;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc;moldname;mingwex] + implicit dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib] + implicit fwks: [] + + +Detecting CXX compiler ABI info compiled with the following output: +Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp + +Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_84b36/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_84b36.dir\build.make CMakeFiles/cmTC_84b36.dir/build +mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' +Building CXX object CMakeFiles/cmTC_84b36.dir/CMakeCXXCompilerABI.cpp.obj +C:\BC\C\mingw64\bin\g++.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1plus.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -version -o C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s +GNU C++14 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include" +#include "..." search starts here: +#include <...> search starts here: + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++ + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32 + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +End of search list. +GNU C++14 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +Compiler executable checksum: 82f0c9785fd37a38ba7b7f8357369a82 +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s +GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30 +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona' +Linking CXX executable cmTC_84b36.exe +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_84b36.dir\link.txt --verbose=1 +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_84b36.dir/objects.a +C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_84b36.dir/objects.a @CMakeFiles\cmTC_84b36.dir\objects1.rsp +C:\BC\C\mingw64\bin\g++.exe -v -Wl,--whole-archive CMakeFiles\cmTC_84b36.dir/objects.a -Wl,--no-whole-archive -o cmTC_84b36.exe -Wl,--out-implib,libcmTC_84b36.dll.a -Wl,--major-image-version,0,--minor-image-version,0 +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe +COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_84b36.exe' '-shared-libgcc' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccmeLhKb.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_84b36.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_84b36.dir/objects.a --no-whole-archive --out-implib libcmTC_84b36.dll.a --major-image-version 0 --minor-image-version 0 -lstdc++ -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_84b36.exe' '-shared-libgcc' '-mtune=core2' '-march=nocona' +mingw32-make.exe[1]: Leaving directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' + + + +Parsed CXX implicit include dir info from above output: rv=done + found start of include info + found start of implicit include info + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + end of search list found + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/include] + implicit include dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include] + + +Parsed CXX implicit link information from above output: + link line regex: [^( *|.*[/\])(ld\.exe|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\]+-)?ld|collect2)[^/\]*( |$)] + ignore line: [Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_84b36/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_84b36.dir\build.make CMakeFiles/cmTC_84b36.dir/build] + ignore line: [mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp'] + ignore line: [Building CXX object CMakeFiles/cmTC_84b36.dir/CMakeCXXCompilerABI.cpp.obj] + ignore line: [C:\BC\C\mingw64\bin\g++.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1plus.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -version -o C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s] + ignore line: [GNU C++14 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include"] + ignore line: [#include "..." search starts here:] + ignore line: [#include <...> search starts here:] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + ignore line: [End of search list.] + ignore line: [GNU C++14 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [Compiler executable checksum: 82f0c9785fd37a38ba7b7f8357369a82] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s] + ignore line: [GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + ignore line: [Linking CXX executable cmTC_84b36.exe] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_84b36.dir\link.txt --verbose=1] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_84b36.dir/objects.a] + ignore line: [C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_84b36.dir/objects.a @CMakeFiles\cmTC_84b36.dir\objects1.rsp] + ignore line: [C:\BC\C\mingw64\bin\g++.exe -v -Wl --whole-archive CMakeFiles\cmTC_84b36.dir/objects.a -Wl --no-whole-archive -o cmTC_84b36.exe -Wl --out-implib libcmTC_84b36.dll.a -Wl --major-image-version 0 --minor-image-version 0 ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe] + ignore line: [COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_84b36.exe' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + link line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccmeLhKb.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_84b36.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_84b36.dir/objects.a --no-whole-archive --out-implib libcmTC_84b36.dll.a --major-image-version 0 --minor-image-version 0 -lstdc++ -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe] ==> ignore + arg [-plugin] ==> ignore + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll] ==> ignore + arg [-plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] ==> ignore + arg [-plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccmeLhKb.res] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [-plugin-opt=-pass-through=-lpthread] ==> ignore + arg [-plugin-opt=-pass-through=-ladvapi32] ==> ignore + arg [-plugin-opt=-pass-through=-lshell32] ==> ignore + arg [-plugin-opt=-pass-through=-luser32] ==> ignore + arg [-plugin-opt=-pass-through=-lkernel32] ==> ignore + arg [-plugin-opt=-pass-through=-liconv] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [--sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64] ==> ignore + arg [-m] ==> ignore + arg [i386pep] ==> ignore + arg [-Bdynamic] ==> ignore + arg [-o] ==> ignore + arg [cmTC_84b36.exe] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o] ==> ignore + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] + arg [--whole-archive] ==> ignore + arg [CMakeFiles\cmTC_84b36.dir/objects.a] ==> ignore + arg [--no-whole-archive] ==> ignore + arg [--out-implib] ==> ignore + arg [libcmTC_84b36.dll.a] ==> ignore + arg [--major-image-version] ==> ignore + arg [0] ==> ignore + arg [--minor-image-version] ==> ignore + arg [0] ==> ignore + arg [-lstdc++] ==> lib [stdc++] + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [-lpthread] ==> lib [pthread] + arg [-ladvapi32] ==> lib [advapi32] + arg [-lshell32] ==> lib [shell32] + arg [-luser32] ==> lib [user32] + arg [-lkernel32] ==> lib [kernel32] + arg [-liconv] ==> lib [iconv] + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] ==> ignore + remove lib [msvcrt] + remove lib [msvcrt] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc] ==> [C:/BC/C/mingw64/lib/gcc] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> [C:/BC/C/mingw64/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> [C:/BC/C/mingw64/lib] + implicit libs: [stdc++;mingw32;gcc_s;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc_s;gcc;moldname;mingwex] + implicit dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib] + implicit fwks: [] + + diff --git a/cmake-build-debug/CMakeFiles/clion-environment.txt b/cmake-build-debug/CMakeFiles/clion-environment.txt new file mode 100644 index 0000000..bd31bb7 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/clion-environment.txt @@ -0,0 +1,4 @@ +ToolSet: w64 6.0 (local)@C:\BC\C\mingw64 +Options: + +Options: \ No newline at end of file diff --git a/cmake-build-debug/CMakeFiles/clion-log.txt b/cmake-build-debug/CMakeFiles/clion-log.txt new file mode 100644 index 0000000..9935687 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/clion-log.txt @@ -0,0 +1,32 @@ +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -DCMAKE_BUILD_TYPE=Debug -G "CodeBlocks - MinGW Makefiles" D:\2021_2\cids-server +-- The C compiler identification is GNU 8.1.0 +-- The CXX compiler identification is GNU 8.1.0 +-- Detecting C compiler ABI info +-- Detecting C compiler ABI info - done +-- Check for working C compiler: C:/BC/C/mingw64/bin/gcc.exe - skipped +-- Detecting C compile features +-- Detecting C compile features - done +-- Detecting CXX compiler ABI info +-- Detecting CXX compiler ABI info - done +-- Check for working CXX compiler: C:/BC/C/mingw64/bin/g++.exe - skipped +-- Detecting CXX compile features +-- Detecting CXX compile features - done +CMake Error at CMakeLists.txt:6 (find_package): + By not providing "FindRapidJSON.cmake" in CMAKE_MODULE_PATH this project + has asked CMake to find a package configuration file provided by + "RapidJSON", but CMake did not find one. + + Could not find a package configuration file provided by "RapidJSON" with + any of the following names: + + RapidJSONConfig.cmake + rapidjson-config.cmake + + Add the installation prefix of "RapidJSON" to CMAKE_PREFIX_PATH or set + "RapidJSON_DIR" to a directory containing one of the above files. If + "RapidJSON" provides a separate development package or SDK, be sure it has + been installed. + + +-- Configuring incomplete, errors occurred! +See also "D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeOutput.log". diff --git a/cmake-build-debug/CMakeFiles/cmake.check_cache b/cmake-build-debug/CMakeFiles/cmake.check_cache new file mode 100644 index 0000000..3dccd73 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/include/db_control/db_control.cpp b/include/db_control/db_control.cpp new file mode 100644 index 0000000..febb51f --- /dev/null +++ b/include/db_control/db_control.cpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +namespace db_control{ + + /* + * param CCmap uuid->ClassInfo + * param skjc 上课节次 + * + */ + void update_lesson_info(std::map &CCmap, unsigned skjc){ + + std::string date_stmt = std::string("select new_week, new_day from calendar"); + std::string find_stmt = std::string(""); + std::string week = "5"; + std::string day = "4"; + try{ +// 获取上课周与星期,及学校日历,主要涉及到补课需求 + nanodbc::result date_row = nanodbc::execute(conn, date_stmt); + week = date_row.get(0); + day = date_row.get(1); + + //补全find_stmt语句 + find_stmt = std::string("SELECT\n" + "U.uuid AS uuid,\n" + "P.kch AS `kch`,\n" + "P.kxh AS `kxh`,\n" + "K.kcm AS `kcm`,\n" + "P.jsxm AS `jsxm`,\n" + "P.jxdd AS `jdxx`,\n" + "FROM\n" + "uuid_jxdd AS U\n" + "INNER JOIN pksj AS P ON U.jxdd = P.jxdd AND U.jsszxqh = P.jsszxqh\n" + "INNER JOIN kcb AS K ON P.kch = K.kch\n" + "WHERE\n" + "P.sksj <= " + skjc.c_str() + " AND\n" + "P.sksj+P.cxjc\t >= " + skjc.c_str() +" AND\n" + "P.skxq = " + day.c_str() + " AND\n" + "SUBSTR(qsz," + week.c_str() + ",1)=\'1\'"); + //查询结果find_stmt + nanodbc::result find_row = nanodbc::execute(conn, find_stmt); + + for(; find_row.next(); ){ + std::string uuid = find_row.get(0); + lesson lesson = lesson(find_row.get(1),find_row.get(2),find_row.get(3),find_row.get(4),find_row.get(5)) + + CCmap.insert(std::make_pair(uuid, lesson)); + } + + }catch(const std::exception& e){ +// 输出至日志 + } + } +} \ No newline at end of file diff --git a/include/mirror/ClassInfo.h b/include/mirror/ClassInfo.h deleted file mode 100644 index 45c475a..0000000 --- a/include/mirror/ClassInfo.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SRC_MIRROR_CLIDESCRIPT_H -#define SRC_MIRROR_CLIDESCRIPT_H - -#pragma once - -#include - -//暂时以string代表课程信息 -using ClassInfo = std::string; -//classinfo中应该有一个bool量表示是否发送过, 发送过置否, 每次更新置真 - -#endif //SRC_MIRROR_CLIDESCRIPT_H diff --git a/include/mirror/ClassInfo.hpp b/include/mirror/ClassInfo.hpp new file mode 100644 index 0000000..2f52744 --- /dev/null +++ b/include/mirror/ClassInfo.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +//暂时以string代表课程信息 + +//classinfo中应该有一个bool量表示是否发送过, 发送过置否, 每次更新置真 + +struct ClassPlace final{ + std::string jsdd_; //教室地点 + unsigned jsszxqh; //教室所在校区号 +}; + +struct ClassInfo final{ + std::string jsdd_; //教师地点 + std::unordered_set lessons_; //课程信息 + bool status_; //true->已发送 +}; diff --git a/include/mirror/Cli.cpp b/include/mirror/Cli.cpp new file mode 100644 index 0000000..3d49754 --- /dev/null +++ b/include/mirror/Cli.cpp @@ -0,0 +1,5 @@ +// +// Created by XM on 2021/5/16. +// + +#include "Cli.hpp" diff --git a/include/mirror/Cli.hpp b/include/mirror/Cli.hpp new file mode 100644 index 0000000..cc3a5f2 --- /dev/null +++ b/include/mirror/Cli.hpp @@ -0,0 +1,15 @@ +// +// Created by XM on 2021/5/16. +// +#pragma once + + +using Cli = std::string; + +// +//class cli{ +// +//}; + + + diff --git a/include/mirror/Message.h b/include/mirror/Message.hpp similarity index 55% rename from include/mirror/Message.h rename to include/mirror/Message.hpp index 8d7ca31..27971b2 100644 --- a/include/mirror/Message.h +++ b/include/mirror/Message.hpp @@ -1,6 +1,3 @@ -#ifndef SRC_MIRROR_MESSAGE_H -#define SRC_MIRROR_MESSAGE_H - #pragma once #include "../Udp.hpp" @@ -12,11 +9,16 @@ //暂时以string代表message的内容 using Content = std::string; +struct Content final{ + std::string time_; + std::string image_url; + std::string message_; + std::string event_; +}; + class Message { private: Content content_; //消息内容 - std::unordered_set dest_; //需要收到消息的目标 + std::unordered_set dest_; //需要收到消息的目标 }; - -#endif //SRC_MIRROR_MESSAGE_H diff --git a/include/mirror/Mirror.cpp b/include/mirror/Mirror.cpp new file mode 100644 index 0000000..46aab78 --- /dev/null +++ b/include/mirror/Mirror.cpp @@ -0,0 +1,225 @@ +#include + + +void Mirror::start() { + //任务队列最大数量 + pool_.setMaxQueueSize(30); + pool_.start(_permanent_thread_num_ + 5;) + + + //提交任务 + + this->pool_.run([this]() { read_config(); }); + //读取配置文件 + this->pool_.run([this]() { update_data_info(); }); + //初始化数据库 + this->pool_.run([this]() { update_data_info(); }); + //更新数据缓存 + this->pool_.run([this]() { listen_cli_beat(); }); + //建立cli链接 + + //输出日志 +} + +void Mirror::read_config() { +//json格式 + static std::string config_file_path{"CenterConfig.txt"}; + static std::ifstream in{config_file_path, std::ios::in}; + Setting set{}; + memset(&set, 0, sizeof(Setting)); + uint next_read_interval{0}; + + auto read_data = [&]() { + if (!in.is_open()) + in.open(config_file_path, std::ios::in); + std::string line{}; + while (in.good()) { + std::getline(in, line, '\n'); + if (line.size() < 2 || line.front() == '/') + continue; + else if (line.find("next_read") != std::string::npos) + next_read_interval = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if (line.find("mir_heart") != std::string::npos) + set.mir_load_record_interval_ = std::stoi( + std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if (line.find("mir_load") != std::string::npos) + set.mir_dblog_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if (line.find("cli_class") != std::string::npos) + set.mir_max_disbeat_time_ = std::stoi( + std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + } + }; + + auto swap = [](Setting *src, Setting *dst) { + Setting *tmp = dst; + dst = src; + src = tmp; + }; + + while (true) { + //读取配置文件 + read_data(); + + //复制到配置副本中 + memcpy(telemeter::setting_copy, &set, sizeof(Setting)); + + //交换主副配置指针 + swap(telemeter::setting_copy, telemeter::setting); //atomic operation + + //挂起该进程 + sleep(next_read_interval * 1000); + } +} + +void Mirror::update_data_info() { +// 发送ip地址 + IP center_ip{0}; + IP this_ip{0}; +// 定义计算服务器负载情况的函数 + auto cal_ser_load = [&]() -> uint8_t { + return 0; + }; + +// 定义计算内存负载情况的函数 + auto cal_mem_load = [&]() -> uint8_t { + return 0; + }; + +// 定义计算网络负载情况的函数 + auto cal_net_load = [&]() -> uint8_t { + return 0; + }; + + auto get_packet = [&](IP, DetailLoadState){ + + }; + + DetailLoadState dtlLoadState{}; + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; +// 设置发送端口 + servaddr.sin_port = htons(myport); +// 设置发送ip + servaddr.sin_addr.s_addr = inet_addr(serverip); + +// 发送缓存 + char* packet = "\0"; + +// 更新间隔 + size_t time = 60; +// 发送的息 + char send_buf[8] = {0}; + +//线程主循环 + while (true) { + + if (time == mir_load_report_interval) { + this_ip; + //calculate ServerLoad + uint8_t serverLoad = cal_ser_load(); + dtlLoadState.serve_load = serverLoad; + //calculate MemoryLoad + uint8_t memLoad = cal_mem_load(); + dtlLoadState.mem_load = memLoad; + //calculate NetworkLoad + uint8_t netLoad = cal_net_load(); + dtlLoadState.net_load_ = netLoad; + + //to_string(8byte) = 4+1+1+1+1 true/false + get_packet(this_ip, dtlLoadState); + time = 1; + } + + if(time == 1){ + get_packet(this_ip, dtlLoadState); + } +// 发送‘心跳包’ + sendto(sock, sendbuf, strlen(sendbuf), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); + + // 重置缓冲 + memset(sendbuf, 0, sizeof(sendbuf)); +// + sleep(setting.mir_heart_beat_interval * 1000); + + time++; + } +} + +//多并发 +void Mirror::listen_cli_beat() { + //set server.onConnect 连接函数 + + //set server.onMessage 接收消息函数(回复消息) + + //set server + + while (true) { + server_; + //接收消息 + + //获取time(为null则加入cli_tree) +// +// if(第一次Content) { +// 返回第一次Content +// }else{ +// 分析时间戳 +// if(版本相同){ +// 返回不需要更新 +// }else{ //版本不同 +// 获取Content +// 返回Content +// } +// } + + + + } +} + +//监听center发送的udp包 +void Mirror::listen_mes() { +// udp + while (true) { + //server.start + } +} + +//清除mirror->client树信息 +void Mirror::clear_cli_data() { + while (true) { + //sleep()24h + } +} + +void Mirror::update_clis_data() { +// db_config 初始化 + const std::string dsn = ""; + const std::string name = ""; + const std::string passwd = ""; + nanodbc::connection conn = nanodbc::connection(dsn, name, passwd); + + while (true) { + for(size_t i = 1; i <= 4; i++) { + db_control::update_lesson_info(conn, this->cli_lesson_, i); + sleep(class_interval * 60 * 1000) + } + + time_sleep_until();//直到每日13:00 + + for(size_t i = 5; i <= 9; i++){ + db_control::update_lesson_info(conn, this->cli_lesson_, i); + sleep(class_interval * 60 * 1000) + } + + time_sleep_until();//直到每日19:00 + + for(size_t i = 10; i <= 12; i++){ + db_control::update_lesson_info(conn, this->cli_lesson_, i); + sleep(class_interval * 60 * 1000) + } + + time_sleep_until(); //直到每日7:30 + } +} + diff --git a/include/mirror/Mirror.h b/include/mirror/Mirror.h deleted file mode 100644 index 328c374..0000000 --- a/include/mirror/Mirror.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef SRC_MIRROR_MIRROR_H -#define SRC_MIRROR_MIRROR_H - - -#include "muduo/base/ThreadPool.h" -#include "muduo/net/InetAddress.h" -#include "muduo/net/TcpServer.h" -#include "muduo/net/EventLoop.h" - -#include "../Telemeter.hpp" -#include "../Type.hpp" //lock free queue -> lfqueue - -#include "ClassInfo.h" -#include "Message.h" - -#include -#include - -class Mirror -{ - private: - DetailLoadState load_; - std::queue mesages_; - std::unordered_map clis_data_; - lfqueue> cookie_; - - muduo::net::EventLoop loop_; - muduo::net::TcpServer server_; - muduo::ThreadPool pool_; -}; - - -#endif //SRC_MIRROR_MIRROR_H \ No newline at end of file diff --git a/include/mirror/Mirror.hpp b/include/mirror/Mirror.hpp new file mode 100644 index 0000000..0e85107 --- /dev/null +++ b/include/mirror/Mirror.hpp @@ -0,0 +1,58 @@ +#include "muduo/base/ThreadPool.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/TcpServer.h" +#include "muduo/net/EventLoop.h" + +#include "../Telemeter.hpp" +#include "../Type.hpp" //lock free queue -> lfqueue + +#include "ClassInfo.hpp" +#include "Message.hpp" + +#include +#include + +class Mirror +{ + class setting{ + unsigned next_read_this_file_interval; + unsigned mir_heart_beat_interval; + unsigned mir_load_report_interval; + unsigned cli_class_info_cache_time; + }; + private: + DetailLoadState load_; + std::queue messages_; + std::unordered_map clis_data_; //uuid->info + lfqueue> cookie_; + std::map cli_lesson_; + nanodbc::connection conn; + + muduo::net::EventLoop loop_; + muduo::net::TcpServer server_; + muduo::ThreadPool pool_; +private: + //mirror start: + + //定时清空IP信息的算法, 例如每晚十二点, + void clear_cli_data(); + + //读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 + void read_config(); + + //更新load情况 + void update_data_info(); + + //开启收听mir心跳的udp线程, mir心跳断线的算法在这里实现, 记录最近一段时间遥测信息的算法也在这里, + void listen_cli_beat(); + + //等待即时消息 + void listen_mes(); + + //更新数据库 + void update_clis_data(); + +public: + void start(); + +}; diff --git a/include/mirror/MirrorConfig.txt b/include/mirror/MirrorConfig.txt index 3d96c48..20de401 100644 --- a/include/mirror/MirrorConfig.txt +++ b/include/mirror/MirrorConfig.txt @@ -1,13 +1,13 @@ -next_read_this_file_interval: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) - +next_read: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) mir_heart_beat_interval: [1]s //心跳的间隔 mir_load_report_interval: [60] //多少个心跳包后更新负载情况 cli_class_info_cache_time: [600]s //课程信息在cli断联后缓存时间, 如果内存紧张可以适当缩短 +class_interval: [55]min mir启动流程 启动EventLoop, 启动Server, 清空clis_data 提交任务 - 定时读取配置文件 + 定时读取配置文 按照更新负载情况的间隔更新load 心跳任务, 心跳计数器的值从配置表中读取 启动等待即时消息的线程 diff --git a/include/mirror/lesson.hpp b/include/mirror/lesson.hpp new file mode 100644 index 0000000..0d0eed8 --- /dev/null +++ b/include/mirror/lesson.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +//#include + +struct lesson final{ + std::string kch_; //课程号 + int kxh_; //课序号 + std::string kcm_; //课程名 + std::string jsxm_; //教师姓名 + std::string jxdd_; //教学地点 + + +// JsonValue get_Event(); + + lesson( std::string kch, unsigned short kxh, std::string kcm, std::string jsxm,std::string jxdd): + kch_(kch), kxh_(kxh), kcm_(kcm), jsxm_(jsxm), jxdd_(jxdd) {} + + friend std::ostream& operator<<(std::ostream& out, const lesson& l){ + out << "kch: " << l.kch_ << ", kxh: " << l.kxh_ << ", kcm: " << l.kcm_ << ", jsxm: " << l.jsxm_ << ", jxdd: " << l.jxdd_; + return out; + } +}; \ No newline at end of file From bd185d462fd2ba648f3bddf7bab75f506bebf0be Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 Date: Mon, 17 May 2021 01:25:48 +0800 Subject: [PATCH 10/16] update --- include/Telemeter.hpp | 13 ++++++++++--- include/mirror/Mirror.cpp | 33 ++++++++++++++++++++++----------- include/mirror/Mirror.hpp | 16 ++++++++++------ include/mirror/MirrorConfig.txt | 2 +- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/include/Telemeter.hpp b/include/Telemeter.hpp index 66ea08f..f9b34ff 100644 --- a/include/Telemeter.hpp +++ b/include/Telemeter.hpp @@ -44,10 +44,10 @@ const constexpr uint _permanent_thread_num_ = 3; //center的常驻线程数量 //mirror的setting, POD type struct Setting { - int center_ip_; - //int backup_center_ip_; uint8_t mir_beat_interval_; - uint8_t //数据库ip? + uint8_t mir_report_interval_; + uint8_t class_cache_time_; + uint8_t class_interval_; }; #endif @@ -68,6 +68,13 @@ namespace telemeter #endif #ifdef SRC_MIRROR_H + + Setting _set_cache_one = {600,1,60,600,55}; + Setting _set_cache_two = {600,1,60,600,55}; + + Setting* setting = &_set_cache_one; + Setting* setting_copy = &_set_cache_two; + #endif diff --git a/include/mirror/Mirror.cpp b/include/mirror/Mirror.cpp index 46aab78..79ee01c 100644 --- a/include/mirror/Mirror.cpp +++ b/include/mirror/Mirror.cpp @@ -2,28 +2,35 @@ void Mirror::start() { - //任务队列最大数量 +//任务队列最大数量 pool_.setMaxQueueSize(30); - pool_.start(_permanent_thread_num_ + 5;) - - - //提交任务 + //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 + pool_.start(static_cast(2 * std::thread::hardware_concurrency())); + auto thd_start = [&](const char* info){ + std::clog << "thread start: " << info << std::endl; + }; - this->pool_.run([this]() { read_config(); }); //读取配置文件 + this->pool_.run([this]() { read_config(); }); + thd_start("read config"); + //发送负载情况 this->pool_.run([this]() { update_data_info(); }); - //初始化数据库 - this->pool_.run([this]() { update_data_info(); }); + thd_start("update data info"); //更新数据缓存 - this->pool_.run([this]() { listen_cli_beat(); }); + this->pool_.run([this]() { update_clis_data() }); + thd_start("updae clients data") + //建立cli链接 + this->pool_.run([this]() { listen_cli_beat(); }); + thd_start("listen clients beat"); //输出日志 } void Mirror::read_config() { -//json格式 - static std::string config_file_path{"CenterConfig.txt"}; + +// 后可以考虑使用json格式 + static std::string config_file_path{"MirrorConfig.txt"}; static std::ifstream in{config_file_path, std::ios::in}; Setting set{}; memset(&set, 0, sizeof(Setting)); @@ -47,6 +54,8 @@ void Mirror::read_config() { else if (line.find("cli_class") != std::string::npos) set.mir_max_disbeat_time_ = std::stoi( std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if(line.find("class_interval") != std::string::bois) + set.class_interval_ = std::stoi( std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); } }; @@ -223,3 +232,5 @@ void Mirror::update_clis_data() { } } + + diff --git a/include/mirror/Mirror.hpp b/include/mirror/Mirror.hpp index 0e85107..12a071d 100644 --- a/include/mirror/Mirror.hpp +++ b/include/mirror/Mirror.hpp @@ -1,3 +1,6 @@ +#ifndef SRC_MIRROR_H +#define SRC_MIRROR_H + #include "muduo/base/ThreadPool.h" #include "muduo/net/InetAddress.h" #include "muduo/net/TcpServer.h" @@ -14,12 +17,6 @@ class Mirror { - class setting{ - unsigned next_read_this_file_interval; - unsigned mir_heart_beat_interval; - unsigned mir_load_report_interval; - unsigned cli_class_info_cache_time; - }; private: DetailLoadState load_; std::queue messages_; @@ -31,6 +28,11 @@ class Mirror muduo::net::EventLoop loop_; muduo::net::TcpServer server_; muduo::ThreadPool pool_; + +// 数据库配置相关,仅在程序开始时使用 + const std::string db_dsn = "MariaDB-server"; + const std::string db_name = "root"; + const std::string db_passwd = "root"; private: //mirror start: @@ -56,3 +58,5 @@ class Mirror void start(); }; + +#endif //SRC_MIRROR_H \ No newline at end of file diff --git a/include/mirror/MirrorConfig.txt b/include/mirror/MirrorConfig.txt index 20de401..21780aa 100644 --- a/include/mirror/MirrorConfig.txt +++ b/include/mirror/MirrorConfig.txt @@ -1,4 +1,4 @@ -next_read: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) +next_read_interval: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) mir_heart_beat_interval: [1]s //心跳的间隔 mir_load_report_interval: [60] //多少个心跳包后更新负载情况 cli_class_info_cache_time: [600]s //课程信息在cli断联后缓存时间, 如果内存紧张可以适当缩短 From 2c7333b97ba2473be946905342324bc9a7303702 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 Date: Fri, 4 Jun 2021 16:44:59 +0800 Subject: [PATCH 11/16] 1 --- .gitignore | 3 + CMakeLists.txt | 62 +- Src/Center/Center.cpp | 405 +++ Src/Center/CenterMain.cpp | 19 + Src/Center/MirDescript.cpp | 0 Src/Common/ServerBase.cpp | 55 + Src/Common/Udp.cpp | 2 + Src/Mirror/Mirror.cpp | 561 ++++ Src/Mirror/MirrorMain.cpp | 18 + Src/Mirror/codec_lib.cpp | 23 + Src/Mirror/db_lib.cpp | 152 + Src/Mirror/json_lib.cpp | 120 + cmake-build-debug/CMakeFiles/clion-log.txt | 34 +- include/Common/ServerBase.hpp | 45 + include/Common/Telemeter.hpp | 121 + include/Common/Udp.hpp | 90 + include/ServerBase.cpp | 57 + include/ServerBase.hpp | 45 + include/Telemeter.hpp | 105 +- include/Third_Lib/boost/any.hpp | 342 ++ .../Third_Lib/cppcodec/base32_crockford.hpp | 91 + .../cppcodec/base32_default_crockford.hpp | 31 + .../Third_Lib/cppcodec/base32_default_hex.hpp | 31 + .../cppcodec/base32_default_rfc4648.hpp | 31 + include/Third_Lib/cppcodec/base32_hex.hpp | 76 + include/Third_Lib/cppcodec/base32_rfc4648.hpp | 76 + .../cppcodec/base64_default_rfc4648.hpp | 31 + .../Third_Lib/cppcodec/base64_default_url.hpp | 31 + .../cppcodec/base64_default_url_unpadded.hpp | 31 + include/Third_Lib/cppcodec/base64_rfc4648.hpp | 73 + include/Third_Lib/cppcodec/base64_url.hpp | 75 + .../cppcodec/base64_url_unpadded.hpp | 48 + include/Third_Lib/cppcodec/data/access.hpp | 328 ++ .../cppcodec/data/raw_result_buffer.hpp | 70 + include/Third_Lib/cppcodec/detail/base32.hpp | 166 + include/Third_Lib/cppcodec/detail/base64.hpp | 132 + include/Third_Lib/cppcodec/detail/codec.hpp | 327 ++ include/Third_Lib/cppcodec/detail/config.hpp | 40 + include/Third_Lib/cppcodec/detail/hex.hpp | 114 + .../cppcodec/detail/stream_codec.hpp | 439 +++ .../Third_Lib/cppcodec/hex_default_lower.hpp | 31 + .../Third_Lib/cppcodec/hex_default_upper.hpp | 31 + include/Third_Lib/cppcodec/hex_lower.hpp | 75 + include/Third_Lib/cppcodec/hex_upper.hpp | 75 + include/Third_Lib/cppcodec/parse_error.hpp | 109 + include/Third_Lib/fmt/core.h | 2744 +++++++++++++++++ include/Third_Lib/muduo/base/AsyncLogging.cc | 136 + include/Third_Lib/muduo/base/AsyncLogging.h | 77 + include/Third_Lib/muduo/base/Atomic.h | 97 + include/Third_Lib/muduo/base/BUILD.bazel | 23 + include/Third_Lib/muduo/base/BlockingQueue.h | 72 + .../muduo/base/BoundedBlockingQueue.h | 101 + include/Third_Lib/muduo/base/CMakeLists.txt | 34 + include/Third_Lib/muduo/base/Condition.cc | 26 + include/Third_Lib/muduo/base/Condition.h | 56 + .../Third_Lib/muduo/base/CountDownLatch.cc | 41 + include/Third_Lib/muduo/base/CountDownLatch.h | 34 + include/Third_Lib/muduo/base/CurrentThread.cc | 77 + include/Third_Lib/muduo/base/CurrentThread.h | 54 + include/Third_Lib/muduo/base/Date.cc | 76 + include/Third_Lib/muduo/base/Date.h | 119 + include/Third_Lib/muduo/base/Exception.cc | 18 + include/Third_Lib/muduo/base/Exception.h | 40 + include/Third_Lib/muduo/base/FileUtil.cc | 181 ++ include/Third_Lib/muduo/base/FileUtil.h | 89 + include/Third_Lib/muduo/base/GzipFile.h | 89 + include/Third_Lib/muduo/base/LogFile.cc | 133 + include/Third_Lib/muduo/base/LogFile.h | 58 + include/Third_Lib/muduo/base/LogStream.cc | 342 ++ include/Third_Lib/muduo/base/LogStream.h | 203 ++ include/Third_Lib/muduo/base/Logging.cc | 227 ++ include/Third_Lib/muduo/base/Logging.h | 159 + include/Third_Lib/muduo/base/Mutex.h | 233 ++ include/Third_Lib/muduo/base/ProcessInfo.cc | 246 ++ include/Third_Lib/muduo/base/ProcessInfo.h | 68 + include/Third_Lib/muduo/base/Singleton.h | 77 + include/Third_Lib/muduo/base/StringPiece.h | 189 ++ include/Third_Lib/muduo/base/Thread.cc | 200 ++ include/Third_Lib/muduo/base/Thread.h | 54 + include/Third_Lib/muduo/base/ThreadLocal.h | 59 + .../muduo/base/ThreadLocalSingleton.h | 82 + include/Third_Lib/muduo/base/ThreadPool.cc | 156 + include/Third_Lib/muduo/base/ThreadPool.h | 67 + include/Third_Lib/muduo/base/TimeZone.cc | 363 +++ include/Third_Lib/muduo/base/TimeZone.h | 52 + include/Third_Lib/muduo/base/Timestamp.cc | 62 + include/Third_Lib/muduo/base/Timestamp.h | 123 + include/Third_Lib/muduo/base/Types.h | 123 + include/Third_Lib/muduo/base/WeakCallback.h | 65 + include/Third_Lib/muduo/base/copyable.h | 19 + include/Third_Lib/muduo/base/noncopyable.h | 20 + .../muduo/base/tests/AsyncLogging_test.cc | 64 + .../muduo/base/tests/Atomic_unittest.cc | 38 + .../muduo/base/tests/BlockingQueue_bench.cc | 106 + .../muduo/base/tests/BlockingQueue_test.cc | 106 + .../base/tests/BoundedBlockingQueue_test.cc | 110 + .../Third_Lib/muduo/base/tests/CMakeLists.txt | 86 + .../muduo/base/tests/Date_unittest.cc | 88 + .../muduo/base/tests/Exception_test.cc | 51 + .../muduo/base/tests/FileUtil_test.cc | 30 + .../Third_Lib/muduo/base/tests/Fork_test.cc | 46 + .../muduo/base/tests/GzipFile_test.cc | 54 + .../muduo/base/tests/LogFile_test.cc | 34 + .../muduo/base/tests/LogStream_bench.cc | 82 + .../muduo/base/tests/LogStream_test.cc | 286 ++ .../muduo/base/tests/Logging_test.cc | 122 + .../Third_Lib/muduo/base/tests/Mutex_test.cc | 82 + .../muduo/base/tests/ProcessInfo_test.cc | 17 + .../base/tests/SingletonThreadLocal_test.cc | 58 + .../muduo/base/tests/Singleton_test.cc | 65 + .../base/tests/ThreadLocalSingleton_test.cc | 58 + .../muduo/base/tests/ThreadLocal_test.cc | 61 + .../muduo/base/tests/ThreadPool_test.cc | 97 + .../muduo/base/tests/Thread_bench.cc | 86 + .../Third_Lib/muduo/base/tests/Thread_test.cc | 91 + .../muduo/base/tests/TimeZone_unittest.cc | 276 ++ .../muduo/base/tests/Timestamp_unittest.cc | 66 + include/Third_Lib/muduo/net/Acceptor.cc | 89 + include/Third_Lib/muduo/net/Acceptor.h | 63 + include/Third_Lib/muduo/net/BUILD.bazel | 51 + include/Third_Lib/muduo/net/Buffer.cc | 58 + include/Third_Lib/muduo/net/Buffer.h | 422 +++ include/Third_Lib/muduo/net/CMakeLists.txt | 69 + include/Third_Lib/muduo/net/Callbacks.h | 82 + include/Third_Lib/muduo/net/Channel.cc | 146 + include/Third_Lib/muduo/net/Channel.h | 113 + include/Third_Lib/muduo/net/Connector.cc | 226 ++ include/Third_Lib/muduo/net/Connector.h | 74 + include/Third_Lib/muduo/net/Endian.h | 65 + include/Third_Lib/muduo/net/EventLoop.cc | 278 ++ include/Third_Lib/muduo/net/EventLoop.h | 166 + .../Third_Lib/muduo/net/EventLoopThread.cc | 77 + include/Third_Lib/muduo/net/EventLoopThread.h | 50 + .../muduo/net/EventLoopThreadPool.cc | 97 + .../Third_Lib/muduo/net/EventLoopThreadPool.h | 69 + include/Third_Lib/muduo/net/InetAddress.cc | 149 + include/Third_Lib/muduo/net/InetAddress.h | 86 + include/Third_Lib/muduo/net/Poller.cc | 29 + include/Third_Lib/muduo/net/Poller.h | 71 + include/Third_Lib/muduo/net/Socket.cc | 128 + include/Third_Lib/muduo/net/Socket.h | 89 + include/Third_Lib/muduo/net/SocketsOps.cc | 316 ++ include/Third_Lib/muduo/net/SocketsOps.h | 64 + include/Third_Lib/muduo/net/TcpClient.cc | 181 ++ include/Third_Lib/muduo/net/TcpClient.h | 90 + include/Third_Lib/muduo/net/TcpConnection.cc | 429 +++ include/Third_Lib/muduo/net/TcpConnection.h | 161 + include/Third_Lib/muduo/net/TcpServer.cc | 118 + include/Third_Lib/muduo/net/TcpServer.h | 120 + include/Third_Lib/muduo/net/Timer.cc | 26 + include/Third_Lib/muduo/net/Timer.h | 63 + include/Third_Lib/muduo/net/TimerId.h | 53 + include/Third_Lib/muduo/net/TimerQueue.cc | 260 ++ include/Third_Lib/muduo/net/TimerQueue.h | 86 + include/Third_Lib/muduo/net/ZlibStream.h | 145 + include/Third_Lib/muduo/net/boilerplate.cc | 15 + include/Third_Lib/muduo/net/boilerplate.h | 32 + include/Third_Lib/muduo/net/http/BUILD.bazel | 9 + .../Third_Lib/muduo/net/http/CMakeLists.txt | 30 + .../Third_Lib/muduo/net/http/HttpContext.cc | 118 + .../Third_Lib/muduo/net/http/HttpContext.h | 72 + .../Third_Lib/muduo/net/http/HttpRequest.h | 187 ++ .../Third_Lib/muduo/net/http/HttpResponse.cc | 47 + .../Third_Lib/muduo/net/http/HttpResponse.h | 79 + .../Third_Lib/muduo/net/http/HttpServer.cc | 100 + include/Third_Lib/muduo/net/http/HttpServer.h | 68 + .../net/http/tests/HttpRequest_unittest.cc | 79 + .../muduo/net/http/tests/HttpServer_test.cc | 150 + .../Third_Lib/muduo/net/inspect/BUILD.bazel | 9 + .../muduo/net/inspect/CMakeLists.txt | 26 + .../Third_Lib/muduo/net/inspect/Inspector.cc | 383 +++ .../Third_Lib/muduo/net/inspect/Inspector.h | 67 + .../muduo/net/inspect/PerformanceInspector.cc | 106 + .../muduo/net/inspect/PerformanceInspector.h | 40 + .../muduo/net/inspect/ProcessInspector.cc | 239 ++ .../muduo/net/inspect/ProcessInspector.h | 38 + .../muduo/net/inspect/SystemInspector.cc | 132 + .../muduo/net/inspect/SystemInspector.h | 37 + .../muduo/net/inspect/tests/BUILD.bazel | 7 + .../muduo/net/inspect/tests/Inspector_test.cc | 15 + .../muduo/net/poller/DefaultPoller.cc | 27 + .../Third_Lib/muduo/net/poller/EPollPoller.cc | 208 ++ .../Third_Lib/muduo/net/poller/EPollPoller.h | 55 + .../Third_Lib/muduo/net/poller/PollPoller.cc | 141 + .../Third_Lib/muduo/net/poller/PollPoller.h | 49 + .../muduo/net/protobuf/BufferStream.h | 56 + .../muduo/net/protobuf/CMakeLists.txt | 15 + .../muduo/net/protobuf/ProtobufCodecLite.cc | 243 ++ .../muduo/net/protobuf/ProtobufCodecLite.h | 192 ++ .../muduo/net/protorpc/CMakeLists.txt | 42 + include/Third_Lib/muduo/net/protorpc/README | 5 + .../muduo/net/protorpc/RpcChannel.cc | 184 ++ .../Third_Lib/muduo/net/protorpc/RpcChannel.h | 152 + .../Third_Lib/muduo/net/protorpc/RpcCodec.cc | 37 + .../Third_Lib/muduo/net/protorpc/RpcCodec.h | 45 + .../muduo/net/protorpc/RpcCodec_test.cc | 81 + .../Third_Lib/muduo/net/protorpc/RpcServer.cc | 68 + .../Third_Lib/muduo/net/protorpc/RpcServer.h | 57 + .../Third_Lib/muduo/net/protorpc/google-inl.h | 84 + .../Third_Lib/muduo/net/protorpc/rpc.proto | 36 + .../muduo/net/protorpc/rpcservice.proto | 44 + .../muduo/net/tests/Buffer_unittest.cc | 170 + .../Third_Lib/muduo/net/tests/CMakeLists.txt | 48 + .../Third_Lib/muduo/net/tests/Channel_test.cc | 112 + .../muduo/net/tests/EchoClient_unittest.cc | 114 + .../muduo/net/tests/EchoServer_unittest.cc | 86 + .../net/tests/EventLoopThreadPool_unittest.cc | 68 + .../net/tests/EventLoopThread_unittest.cc | 48 + .../muduo/net/tests/EventLoop_unittest.cc | 42 + .../muduo/net/tests/InetAddress_unittest.cc | 70 + .../muduo/net/tests/TcpClient_reg1.cc | 29 + .../muduo/net/tests/TcpClient_reg2.cc | 30 + .../muduo/net/tests/TcpClient_reg3.cc | 24 + .../muduo/net/tests/TimerQueue_unittest.cc | 66 + .../muduo/net/tests/ZlibStream_unittest.cc | 91 + include/Type.hpp | 12 - include/Udp.hpp | 34 +- include/center/MirDescript.h | 73 +- include/center/TcpEcho.h | 22 +- include/center/center.h | 70 +- include/center_head | 3 + include/common_head | 3 + include/db_control/db_control.cpp | 119 +- include/json_control/json_control.cpp | 103 + include/mirror/BackGround.hpp | 11 + include/mirror/ClassInfo.hpp | 18 - include/mirror/ClassMes.hpp | 17 + include/mirror/Cli.cpp | 5 - include/mirror/Cli.hpp | 19 +- include/mirror/CliDescript.hpp | 22 + include/mirror/Message.hpp | 24 +- include/mirror/Mirror.cpp | 352 ++- include/mirror/Mirror.hpp | 156 +- include/mirror/MirrorConfig.txt | 4 +- include/mirror/Util.hpp | 60 + include/mirror/lesson.hpp | 21 +- include/mirror_head | 7 + 237 files changed, 25179 insertions(+), 384 deletions(-) create mode 100644 Src/Center/Center.cpp create mode 100644 Src/Center/CenterMain.cpp create mode 100644 Src/Center/MirDescript.cpp create mode 100644 Src/Common/ServerBase.cpp create mode 100644 Src/Common/Udp.cpp create mode 100644 Src/Mirror/Mirror.cpp create mode 100644 Src/Mirror/MirrorMain.cpp create mode 100644 Src/Mirror/codec_lib.cpp create mode 100644 Src/Mirror/db_lib.cpp create mode 100644 Src/Mirror/json_lib.cpp create mode 100644 include/Common/ServerBase.hpp create mode 100644 include/Common/Telemeter.hpp create mode 100644 include/Common/Udp.hpp create mode 100644 include/ServerBase.cpp create mode 100644 include/ServerBase.hpp create mode 100644 include/Third_Lib/boost/any.hpp create mode 100644 include/Third_Lib/cppcodec/base32_crockford.hpp create mode 100644 include/Third_Lib/cppcodec/base32_default_crockford.hpp create mode 100644 include/Third_Lib/cppcodec/base32_default_hex.hpp create mode 100644 include/Third_Lib/cppcodec/base32_default_rfc4648.hpp create mode 100644 include/Third_Lib/cppcodec/base32_hex.hpp create mode 100644 include/Third_Lib/cppcodec/base32_rfc4648.hpp create mode 100644 include/Third_Lib/cppcodec/base64_default_rfc4648.hpp create mode 100644 include/Third_Lib/cppcodec/base64_default_url.hpp create mode 100644 include/Third_Lib/cppcodec/base64_default_url_unpadded.hpp create mode 100644 include/Third_Lib/cppcodec/base64_rfc4648.hpp create mode 100644 include/Third_Lib/cppcodec/base64_url.hpp create mode 100644 include/Third_Lib/cppcodec/base64_url_unpadded.hpp create mode 100644 include/Third_Lib/cppcodec/data/access.hpp create mode 100644 include/Third_Lib/cppcodec/data/raw_result_buffer.hpp create mode 100644 include/Third_Lib/cppcodec/detail/base32.hpp create mode 100644 include/Third_Lib/cppcodec/detail/base64.hpp create mode 100644 include/Third_Lib/cppcodec/detail/codec.hpp create mode 100644 include/Third_Lib/cppcodec/detail/config.hpp create mode 100644 include/Third_Lib/cppcodec/detail/hex.hpp create mode 100644 include/Third_Lib/cppcodec/detail/stream_codec.hpp create mode 100644 include/Third_Lib/cppcodec/hex_default_lower.hpp create mode 100644 include/Third_Lib/cppcodec/hex_default_upper.hpp create mode 100644 include/Third_Lib/cppcodec/hex_lower.hpp create mode 100644 include/Third_Lib/cppcodec/hex_upper.hpp create mode 100644 include/Third_Lib/cppcodec/parse_error.hpp create mode 100644 include/Third_Lib/fmt/core.h create mode 100644 include/Third_Lib/muduo/base/AsyncLogging.cc create mode 100644 include/Third_Lib/muduo/base/AsyncLogging.h create mode 100644 include/Third_Lib/muduo/base/Atomic.h create mode 100644 include/Third_Lib/muduo/base/BUILD.bazel create mode 100644 include/Third_Lib/muduo/base/BlockingQueue.h create mode 100644 include/Third_Lib/muduo/base/BoundedBlockingQueue.h create mode 100644 include/Third_Lib/muduo/base/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/base/Condition.cc create mode 100644 include/Third_Lib/muduo/base/Condition.h create mode 100644 include/Third_Lib/muduo/base/CountDownLatch.cc create mode 100644 include/Third_Lib/muduo/base/CountDownLatch.h create mode 100644 include/Third_Lib/muduo/base/CurrentThread.cc create mode 100644 include/Third_Lib/muduo/base/CurrentThread.h create mode 100644 include/Third_Lib/muduo/base/Date.cc create mode 100644 include/Third_Lib/muduo/base/Date.h create mode 100644 include/Third_Lib/muduo/base/Exception.cc create mode 100644 include/Third_Lib/muduo/base/Exception.h create mode 100644 include/Third_Lib/muduo/base/FileUtil.cc create mode 100644 include/Third_Lib/muduo/base/FileUtil.h create mode 100644 include/Third_Lib/muduo/base/GzipFile.h create mode 100644 include/Third_Lib/muduo/base/LogFile.cc create mode 100644 include/Third_Lib/muduo/base/LogFile.h create mode 100644 include/Third_Lib/muduo/base/LogStream.cc create mode 100644 include/Third_Lib/muduo/base/LogStream.h create mode 100644 include/Third_Lib/muduo/base/Logging.cc create mode 100644 include/Third_Lib/muduo/base/Logging.h create mode 100644 include/Third_Lib/muduo/base/Mutex.h create mode 100644 include/Third_Lib/muduo/base/ProcessInfo.cc create mode 100644 include/Third_Lib/muduo/base/ProcessInfo.h create mode 100644 include/Third_Lib/muduo/base/Singleton.h create mode 100644 include/Third_Lib/muduo/base/StringPiece.h create mode 100644 include/Third_Lib/muduo/base/Thread.cc create mode 100644 include/Third_Lib/muduo/base/Thread.h create mode 100644 include/Third_Lib/muduo/base/ThreadLocal.h create mode 100644 include/Third_Lib/muduo/base/ThreadLocalSingleton.h create mode 100644 include/Third_Lib/muduo/base/ThreadPool.cc create mode 100644 include/Third_Lib/muduo/base/ThreadPool.h create mode 100644 include/Third_Lib/muduo/base/TimeZone.cc create mode 100644 include/Third_Lib/muduo/base/TimeZone.h create mode 100644 include/Third_Lib/muduo/base/Timestamp.cc create mode 100644 include/Third_Lib/muduo/base/Timestamp.h create mode 100644 include/Third_Lib/muduo/base/Types.h create mode 100644 include/Third_Lib/muduo/base/WeakCallback.h create mode 100644 include/Third_Lib/muduo/base/copyable.h create mode 100644 include/Third_Lib/muduo/base/noncopyable.h create mode 100644 include/Third_Lib/muduo/base/tests/AsyncLogging_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/Atomic_unittest.cc create mode 100644 include/Third_Lib/muduo/base/tests/BlockingQueue_bench.cc create mode 100644 include/Third_Lib/muduo/base/tests/BlockingQueue_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/BoundedBlockingQueue_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/base/tests/Date_unittest.cc create mode 100644 include/Third_Lib/muduo/base/tests/Exception_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/FileUtil_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/Fork_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/GzipFile_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/LogFile_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/LogStream_bench.cc create mode 100644 include/Third_Lib/muduo/base/tests/LogStream_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/Logging_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/Mutex_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/ProcessInfo_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/SingletonThreadLocal_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/Singleton_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/ThreadLocalSingleton_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/ThreadLocal_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/ThreadPool_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/Thread_bench.cc create mode 100644 include/Third_Lib/muduo/base/tests/Thread_test.cc create mode 100644 include/Third_Lib/muduo/base/tests/TimeZone_unittest.cc create mode 100644 include/Third_Lib/muduo/base/tests/Timestamp_unittest.cc create mode 100644 include/Third_Lib/muduo/net/Acceptor.cc create mode 100644 include/Third_Lib/muduo/net/Acceptor.h create mode 100644 include/Third_Lib/muduo/net/BUILD.bazel create mode 100644 include/Third_Lib/muduo/net/Buffer.cc create mode 100644 include/Third_Lib/muduo/net/Buffer.h create mode 100644 include/Third_Lib/muduo/net/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/net/Callbacks.h create mode 100644 include/Third_Lib/muduo/net/Channel.cc create mode 100644 include/Third_Lib/muduo/net/Channel.h create mode 100644 include/Third_Lib/muduo/net/Connector.cc create mode 100644 include/Third_Lib/muduo/net/Connector.h create mode 100644 include/Third_Lib/muduo/net/Endian.h create mode 100644 include/Third_Lib/muduo/net/EventLoop.cc create mode 100644 include/Third_Lib/muduo/net/EventLoop.h create mode 100644 include/Third_Lib/muduo/net/EventLoopThread.cc create mode 100644 include/Third_Lib/muduo/net/EventLoopThread.h create mode 100644 include/Third_Lib/muduo/net/EventLoopThreadPool.cc create mode 100644 include/Third_Lib/muduo/net/EventLoopThreadPool.h create mode 100644 include/Third_Lib/muduo/net/InetAddress.cc create mode 100644 include/Third_Lib/muduo/net/InetAddress.h create mode 100644 include/Third_Lib/muduo/net/Poller.cc create mode 100644 include/Third_Lib/muduo/net/Poller.h create mode 100644 include/Third_Lib/muduo/net/Socket.cc create mode 100644 include/Third_Lib/muduo/net/Socket.h create mode 100644 include/Third_Lib/muduo/net/SocketsOps.cc create mode 100644 include/Third_Lib/muduo/net/SocketsOps.h create mode 100644 include/Third_Lib/muduo/net/TcpClient.cc create mode 100644 include/Third_Lib/muduo/net/TcpClient.h create mode 100644 include/Third_Lib/muduo/net/TcpConnection.cc create mode 100644 include/Third_Lib/muduo/net/TcpConnection.h create mode 100644 include/Third_Lib/muduo/net/TcpServer.cc create mode 100644 include/Third_Lib/muduo/net/TcpServer.h create mode 100644 include/Third_Lib/muduo/net/Timer.cc create mode 100644 include/Third_Lib/muduo/net/Timer.h create mode 100644 include/Third_Lib/muduo/net/TimerId.h create mode 100644 include/Third_Lib/muduo/net/TimerQueue.cc create mode 100644 include/Third_Lib/muduo/net/TimerQueue.h create mode 100644 include/Third_Lib/muduo/net/ZlibStream.h create mode 100644 include/Third_Lib/muduo/net/boilerplate.cc create mode 100644 include/Third_Lib/muduo/net/boilerplate.h create mode 100644 include/Third_Lib/muduo/net/http/BUILD.bazel create mode 100644 include/Third_Lib/muduo/net/http/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/net/http/HttpContext.cc create mode 100644 include/Third_Lib/muduo/net/http/HttpContext.h create mode 100644 include/Third_Lib/muduo/net/http/HttpRequest.h create mode 100644 include/Third_Lib/muduo/net/http/HttpResponse.cc create mode 100644 include/Third_Lib/muduo/net/http/HttpResponse.h create mode 100644 include/Third_Lib/muduo/net/http/HttpServer.cc create mode 100644 include/Third_Lib/muduo/net/http/HttpServer.h create mode 100644 include/Third_Lib/muduo/net/http/tests/HttpRequest_unittest.cc create mode 100644 include/Third_Lib/muduo/net/http/tests/HttpServer_test.cc create mode 100644 include/Third_Lib/muduo/net/inspect/BUILD.bazel create mode 100644 include/Third_Lib/muduo/net/inspect/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/net/inspect/Inspector.cc create mode 100644 include/Third_Lib/muduo/net/inspect/Inspector.h create mode 100644 include/Third_Lib/muduo/net/inspect/PerformanceInspector.cc create mode 100644 include/Third_Lib/muduo/net/inspect/PerformanceInspector.h create mode 100644 include/Third_Lib/muduo/net/inspect/ProcessInspector.cc create mode 100644 include/Third_Lib/muduo/net/inspect/ProcessInspector.h create mode 100644 include/Third_Lib/muduo/net/inspect/SystemInspector.cc create mode 100644 include/Third_Lib/muduo/net/inspect/SystemInspector.h create mode 100644 include/Third_Lib/muduo/net/inspect/tests/BUILD.bazel create mode 100644 include/Third_Lib/muduo/net/inspect/tests/Inspector_test.cc create mode 100644 include/Third_Lib/muduo/net/poller/DefaultPoller.cc create mode 100644 include/Third_Lib/muduo/net/poller/EPollPoller.cc create mode 100644 include/Third_Lib/muduo/net/poller/EPollPoller.h create mode 100644 include/Third_Lib/muduo/net/poller/PollPoller.cc create mode 100644 include/Third_Lib/muduo/net/poller/PollPoller.h create mode 100644 include/Third_Lib/muduo/net/protobuf/BufferStream.h create mode 100644 include/Third_Lib/muduo/net/protobuf/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.cc create mode 100644 include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.h create mode 100644 include/Third_Lib/muduo/net/protorpc/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/net/protorpc/README create mode 100644 include/Third_Lib/muduo/net/protorpc/RpcChannel.cc create mode 100644 include/Third_Lib/muduo/net/protorpc/RpcChannel.h create mode 100644 include/Third_Lib/muduo/net/protorpc/RpcCodec.cc create mode 100644 include/Third_Lib/muduo/net/protorpc/RpcCodec.h create mode 100644 include/Third_Lib/muduo/net/protorpc/RpcCodec_test.cc create mode 100644 include/Third_Lib/muduo/net/protorpc/RpcServer.cc create mode 100644 include/Third_Lib/muduo/net/protorpc/RpcServer.h create mode 100644 include/Third_Lib/muduo/net/protorpc/google-inl.h create mode 100644 include/Third_Lib/muduo/net/protorpc/rpc.proto create mode 100644 include/Third_Lib/muduo/net/protorpc/rpcservice.proto create mode 100644 include/Third_Lib/muduo/net/tests/Buffer_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/CMakeLists.txt create mode 100644 include/Third_Lib/muduo/net/tests/Channel_test.cc create mode 100644 include/Third_Lib/muduo/net/tests/EchoClient_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/EchoServer_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/EventLoopThreadPool_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/EventLoopThread_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/EventLoop_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/InetAddress_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/TcpClient_reg1.cc create mode 100644 include/Third_Lib/muduo/net/tests/TcpClient_reg2.cc create mode 100644 include/Third_Lib/muduo/net/tests/TcpClient_reg3.cc create mode 100644 include/Third_Lib/muduo/net/tests/TimerQueue_unittest.cc create mode 100644 include/Third_Lib/muduo/net/tests/ZlibStream_unittest.cc delete mode 100644 include/Type.hpp create mode 100644 include/center_head create mode 100644 include/common_head create mode 100644 include/json_control/json_control.cpp create mode 100644 include/mirror/BackGround.hpp delete mode 100644 include/mirror/ClassInfo.hpp create mode 100644 include/mirror/ClassMes.hpp delete mode 100644 include/mirror/Cli.cpp create mode 100644 include/mirror/CliDescript.hpp create mode 100644 include/mirror/Util.hpp create mode 100644 include/mirror_head diff --git a/.gitignore b/.gitignore index f77e472..433a520 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ build/ lib/ +.idea/ +cmake-build-debug/ +Lib/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f298f9..50238fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,60 @@ -cmake_minimum_required(VERSION 3.0) - -project(pro) +cmake_minimum_required(VERSION 3.00) +project(cids_server_new) +#Global Setting SET(CMAKE_CXX_FLAGS -pthread) -find_package(RapidJSON REQUIRED) + +SET(CMAKE_CXX_STANDARD 14) + +#Thir Lib + + #find- nanodbc +if(NOT TARGET nanodbc) + find_package(nanodbc CONFIG REQUIRED) +endif() + + #find- rapidjson +find_package(RapidJson REQUIRED) + + #already put muduo in the project + +#add include +include_directories(Include) +include_directories(Include/Third_Lib) include_directories(${RapidJSON_INCLUDE_DIR}) -include_directories(include) +#muduo in Include/Third_lib +#nanodbc in Include/Third_lib + +#add lib +link_directories(Lib) + +#My src +aux_source_directory(Src/Center CENTER_SRC) +aux_source_directory(Src/Mirror MIRROR_SRC) +aux_source_directory(Src/Common COMMON_SRC) + +#生成可执行文件 + +add_executable(center ${CENTER_SRC} ${COMMON_SRC}) +add_executable(mirror ${MIRROR_SRC} ${COMMON_SRC}) + +#Center绑定包 +target_link_libraries(center libmuduo_base.a libmuduo_net.a) #绑定muduo包 + -link_directories("lib") +#Center修改输出属性 +set_target_properties(center PROPERTIES OUTPUT_NAME cids_Center) +set_target_properties(center PROPERTIES PREFIX "") +set_target_properties(center PROPERTIES SUFFIX "") -add_executable(testC test.cpp) +#Mirror绑定包 +target_link_libraries(mirror libmuduo_base.a libmuduo_net.a) #绑定muduo包 +target_link_libraries(mirror ${RapidJSON_LIBS}) #绑定rapidjson包 +target_link_libraries(mirror nanodbc) #绑定nanodbc包 -target_link_libraries(testC ${RapidJSON_LIBS}) -target_link_libraries(testC libmuduo_net.a libmuduo_base.a) -target_link_libraries(testC libnanodbc.a) +#Mirror修改输出树形 +set_target_properties(mirror PROPERTIES OUTPUT_NAME cids_Mirror) +set_target_properties(mirror PROPERTIES PREFIX "") +set_target_properties(mirror PROPERTIES SUFFIX "") diff --git a/Src/Center/Center.cpp b/Src/Center/Center.cpp new file mode 100644 index 0000000..f147e37 --- /dev/null +++ b/Src/Center/Center.cpp @@ -0,0 +1,405 @@ +#include + +void center::start() +{ + //任务队列最大数量 + pool_.setMaxQueueSize(30); + //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 + pool_.start(static_cast(2 * std::thread::hardware_concurrency())); + auto thd_start = [&](const char* info){ + std::clog << "thread start: " << info << std::endl; + }; + //提交定时读取配置文件的任务,监听cli登录, mir心跳的任务 + this->pool_.run( [this](){ read_config(); }); + thd_start("read config"); + this->pool_.run( [this](){ wait_cli_login(); }); + thd_start("wait cli login"); + this->pool_.run( [this](){ listen_mir_beat(); }); + thd_start("listen mir beat"); + this->pool_.run( [this](){ clear_mirs_data(); }); + thd_start("clear mir data"); + + //设置原子锁的值 + this->atom_mutex_ = false; + + //日志输出的文件和文件路径在telemeter命名空间下 + +} + +void center::read_config() +{ + static std::string config_file_path {"CenterConfig.txt"}; + static std::ifstream in {config_file_path, std::ios::in}; + Setting set {}; memset(&set, 0, sizeof(Setting)); + uint next_read_interval {0}; + + auto read_data = [&]() { + if(!in.is_open()) + in.open(config_file_path, std::ios::in); + std::string line {}; + while (in.good()) + { + std::getline(in, line, '\n'); + if(line.size() < 2 || line.front() == '/') + continue; + else if(line.find("next_read") != std::string::npos) + next_read_interval = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if(line.find("load_record") != std::string::npos) + set.mir_load_record_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if(line.find("load_dblog") != std::string::npos) + set.mir_dblog_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if(line.find("max_disbeat") != std::string::npos) + set.mir_max_disbeat_time_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if(line.find("login_cache") != std::string::npos) + set.cli_login_cache_time_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if(line.find("balance") != std::string::npos) + set.load_balance_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if(line.find("clear_mirs") != std::string::npos) + set.clear_mirs_data_time_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + } + }; + + auto swap = [](Setting* src, Setting* dst){ + Setting* tmp = dst; + dst = src; + src = tmp; + }; + + while(true) + { + //读取配置文件 + read_data(); + + //复制到配置副本中 + memcpy(telemeter::setting_copy, &set, sizeof(Setting)); + + //交换主副配置指针 + swap(telemeter::setting_copy, telemeter::setting); //atomic operation + + //挂起该进程 + sleep(next_read_interval * 1000); + } +} + +void center::wait_cli_login() +{ + static IP available_mir {0}; + static size_t login_count {0}; + auto load_balance_warpper = [&]() + { + available_mir = this->load_balance(); + }; + + //纠正树形结构中cli信息的任务, 将交给线程池异步执行 + auto correct_tree_structure = [&](uuid cli_id){ + for(auto& kvp : mirs_data_) + { + if(kvp.second.contains(cli_id)) + { + kvp.second.erase_cli(cli_id); + } + } + + }; + + //用于接收数据的缓冲区 + std::array packet {0}; + std::array uidbuf {0}; + std::array statebuf {0}; + //创建socket + int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + //服务端addr和客户端addr, 后者保存发送方的信息 + struct sockaddr_in addr_serv, addr_cli; + + //初始化addr_serv, 无需初始化addr_cli + memset(&addr_serv, 0, sizeof(sockaddr_in)); + memset(&addr_cli, 0, sizeof(sockaddr_in)); + addr_serv.sin_family = AF_INET; //使用IPV4地址 + addr_serv.sin_port = htons(static_cast(port::kCLI_LOGIN_)); //端口 + /* INADDR_ANY表示不管是哪个网卡接收到数据,只要目的端口是SERV_PORT,就会被该应用程序接收到 */ + //int n = inet_aton("172.24.153.237", &addr_serv.sin_addr); + addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址 + unsigned int place_holder_1 = sizeof(addr_cli); + //const int place_holder_2 = 1; + + //进入循环前统一进行异常检测 + if(sock_fd < 0) + throw std::runtime_error("Init socket failed in port::kCLI_LOGIN_"); + //解决bind绑定失败的遗留 + //setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&place_holder_2,sizeof(place_holder_2)); + int ret = bind(sock_fd, (sockaddr*)&addr_serv, sizeof(addr_serv)); + if(ret < 0) + throw std::runtime_error("Bind socket failed in port::kCLI_LOGIN_"); + + //线程主循环 + while(true) + { + int recv_num = recvfrom(sock_fd, packet.data(), packet.size(), MSG_WAITALL, (sockaddr*)&addr_cli, &place_holder_1); + //MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。 + //如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。 + + //可能是阻塞超时, 进行下次循环 + if(recv_num < 0) + continue; + + //按照协议格式进行解析, 并且得到ip等其他信息 + memcpy(uidbuf.data(), packet.data(), protocal::kCLI_LOGIN_UID_); + size_t uid = std::atol(uidbuf.data()); + memcpy(statebuf.data(), packet.data() + protocal::kCLI_LOGIN_UID_, protocal::kCLI_LOGIN_STATE_); + size_t state = statebuf[0]; + //state暂时不做处理 + + //是否在cookie中找到登陆记录 + bool cached {false}; + + //登录或者重新连接 + if(!this->cookie_.empty()) + { + while(true) + { + //空闲状态可以使用 + if(atom_mutex_ == false) + { + //进入临界区 + atom_mutex_ = true; + for(uuid cache : cookie_) + { + //找到登陆痕迹直接掠过 + if(cache == uid) + { + cached = true; + break; + } + } + //结束临界区 + atom_mutex_ = false; + break; + } + else //锁被pop队头或者push任务的任务使用中 + { + continue; + } + } + if(cached == true) + { + //此处应当分析包中state来统计网络不畅的情况, 暂时忽略 + continue; + } + } + + //cookie为空或者没有找到时, 记录cli登录信息 + if(cached == false) + { + //回复可用mir地址 + int send_num = sendto(sock_fd, &available_mir, sizeof(available_mir), 0, (sockaddr*)&addr_cli, sizeof(addr_cli)); + login_count++; + + //数据库记录日志 + //dblog(cli_login, uid); + if(this->all_cli_.count(uid) == 0) + this->all_cli_.insert(uid); + else + this->pool_.run(std::bind(correct_tree_structure, uid)); + while(true) + { + //空闲状态可以使用 + if(atom_mutex_ == false) + { + //进入临界区 + atom_mutex_ = true; + //这个push操作似乎不需要上锁 + cookie_.push_back(uid); + //结束临界区 + atom_mutex_ = false; + + //设置一段时间后pop掉队头的任务 + this->pool_.run( [this](){ + sleep(telemeter::setting->cli_login_cache_time_); + while(true) + { + if(atom_mutex_ == false) + { + atom_mutex_ = true; + cookie_.pop_front(); + atom_mutex_ = false; + } + else + continue; + } + }); + break; + } + else //锁被pop队头或者查询任务使用中 + { + continue; + } + } + } + //重置输入缓冲区 + packet.fill(0); + + if(login_count >= telemeter::setting->load_balance_interval_) + { + //提交给线程池而不阻塞在io线程, 对available_mir的修改是跨线程操作变量 + this->pool_.run(load_balance_warpper); + login_count = 0; + } + } +} + +void center::listen_mir_beat() +{ + IP mir_ip {0}; //心跳的mir ip + size_t all_beat_count {0}; //用于判活算法 + + //用于接收数据的缓冲区 + std::array packet {0}; + std::array ipbuf {0}; + std::array loadbuf {0}; + //创建socket + int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + //服务端addr和客户端addr, 后者保存发送方的信息 + struct sockaddr_in addr_serv, addr_mir; + + //初始化addr_serv, 无需初始化addr_cli + memset(&addr_serv, 0, sizeof(sockaddr_in)); + memset(&addr_mir, 0, sizeof(sockaddr_in)); + addr_serv.sin_family = AF_INET; //使用IPV4地址 + addr_serv.sin_port = htons(port::kMIR_BEAT_); //端口 + /* INADDR_ANY表示不管是哪个网卡接收到数据,只要目的端口是SERV_PORT,就会被该应用程序接收到 */ + addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址 + unsigned int place_holder_1 = sizeof(addr_mir); + + //进入循环前统一进行异常检测 + if(sock_fd < 0) + throw std::runtime_error("Init socket failed in port::kMIR_BEAT_"); + if(bind(sock_fd, (sockaddr*)&addr_serv, sizeof(addr_serv)) < 0) + throw std::runtime_error("Bind socket failed in port::KMIR_BEAT_"); + + + //线程主循环 + while(true) + { + int recv_num = recvfrom(sock_fd, packet.data(), packet.size(), MSG_WAITALL, (sockaddr*)&addr_mir, &place_holder_1); + //MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。 + //如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。 + + //可能是阻塞超时, 进行下次循环 + if(recv_num < 0) + continue; + + //按照协议格式进行解析, 并且得到ip等其他信息 + memcpy(ipbuf.data(), packet.data(), protocal::kMIR_BEAT_IP_); + memcpy(loadbuf.data(), packet.data() + protocal::kMIR_BEAT_IP_, protocal::kMIR_BEAT_LOAD_); + + mir_ip = (ipbuf[0] << 24) + (ipbuf[1] << 16) + (ipbuf[2] << 8) + (ipbuf[3]); + if(mirs_data_.count(mir_ip) == 0) + { + mirs_data_.insert({mir_ip, MirDescript()}); + //dblog(MIR_LIGIN); + } + else + { + mirs_data_[mir_ip].reset_beat(telemeter::setting->mir_max_disbeat_time_); + //记录负载情况到缓存 + //mirs_data_[mir_ip].recordLoad(); + all_beat_count++; + if(all_beat_count >= mirs_data_.size() - 1) + { + for(auto& kvp : mirs_data_) + { + if(kvp.second.decre_and_get_beat() <= 0); + { + //说明有mir掉线了 + int i = 3; //占位避免编译器报warning + //dblog(MIR_DISCONECT); + mirs_data_.erase(kvp.first); + } + } + } + } + + } +} + +void center::clear_mirs_data() +{ + //while(true) + { + //sleep(nowtime - nextzeropoint + setting->clear_mirsdata_time); + //mirs_data_.clear(); + //all_cli_.clear(); + } +} + +IP center::load_balance() +{ + //暂时不优化 + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::light) + return kvp.first; + } + + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::medium) + return kvp.first; + } + + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::untapped) + { + kvp.second.set_load_level(LoadLevel::light); + return kvp.first; + } + } + + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::heavy) + { + return kvp.first; + } + } + + //没有任何一个可用的服务器 + throw std::runtime_error("No available mir to dispatch"); +} + +void center::log_info(std::exception& e, const char* crush_file) +{ + //以后要改到json里面, 还缺详细个数的输出 + static std::ofstream log(crush_file, std::ios::out); + if(!log.is_open()) + log.open(crush_file, std::ios::out); + log <<"crush time: " << time(nullptr) <<"\nreason: " << e.what() << std::endl; + + log << "Mirrors & dispatched client:\n"; + for(auto& kvp : mirs_data_) + { + log << "ip: " << kvp.first + << " load state: " << tostring(kvp.second.get_load_level()) << '\n'; + log << "dispatched client: \n"; + for(auto uid : kvp.second.get_dispatched_cli()) + { + log << uid << '\n'; + } + } + + log << "cookie mutex: " << atom_mutex_ << '\n'; + if(cookie_.size() > 0) + { + log << "cookie :\n"; + for(auto uid : cookie_) + { + log << uid << '\n'; + } + } +} + + + + + diff --git a/Src/Center/CenterMain.cpp b/Src/Center/CenterMain.cpp new file mode 100644 index 0000000..ee6095e --- /dev/null +++ b/Src/Center/CenterMain.cpp @@ -0,0 +1,19 @@ +#include + +#include + +int main() +{ + static const char* crush_log = "../crush.txt"; + + center ctr; + try + { + ctr.start(); + } + catch(std::exception& e) + { + std::cerr << e.what() << '\n'; + ctr.log_info(e, crush_log); + } +} diff --git a/Src/Center/MirDescript.cpp b/Src/Center/MirDescript.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Src/Common/ServerBase.cpp b/Src/Common/ServerBase.cpp new file mode 100644 index 0000000..0369085 --- /dev/null +++ b/Src/Common/ServerBase.cpp @@ -0,0 +1,55 @@ +#include + +bool scu_time::operator=(const scu_time &rhs) { + return this->hour == rhs.hour && this->minute == rhs.minute; +} + +scu_time scu_time::operator-(const scu_time &rhs) const{ + size_t lMinute; + if (*this < rhs) + lMinute = (this->hour + 24) * 60 + this->minute; + else + lMinute = this->hour * 60 + this->minute; + size_t rMinute = rhs.hour * 60 + rhs.minute; + size_t nHour = (lMinute - rMinute) % 60; + size_t nMinute = (lMinute - rMinute) - nHour * 60; + return scu_time(nHour, nMinute); +} + +bool scu_time::operator<(const scu_time &rhs) const { + if (this->hour > rhs.hour) { + return false; + } else { + if (this->minute >= rhs.minute) { + return false; + } else { + return true; + } + } +} + +bool scu_time::operator<=(const scu_time &rhs) const { + if (this->hour > rhs.hour) { + return false; + } else { + if (this->minute > rhs.minute) + return false; + else + return true; + } +} + +unsigned scu_time::toSeconds() { + return this->hour * 3600 + this->minute * 60; +} + + +scu_time scu_time::toScutime(const muduo::Timestamp ×tamp){ + long allSeconds = std::stol(timestamp.toString()); + int seconds = allSeconds % 86400; + size_t hour = seconds / 3600; + size_t minute = (seconds - hour * 3600) / 60; + return scu_time(hour, minute); +} + + diff --git a/Src/Common/Udp.cpp b/Src/Common/Udp.cpp new file mode 100644 index 0000000..cff7dec --- /dev/null +++ b/Src/Common/Udp.cpp @@ -0,0 +1,2 @@ +#include + diff --git a/Src/Mirror/Mirror.cpp b/Src/Mirror/Mirror.cpp new file mode 100644 index 0000000..27ff94c --- /dev/null +++ b/Src/Mirror/Mirror.cpp @@ -0,0 +1,561 @@ +#include + +//如果最后一节课.置空字符串+置零 +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; + +void Mirror::start() { + + //初始化配置文件及各数据 + this->init(); + + //任务队列最大数量 + + pool_.setMaxQueueSize(30); + //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 + pool_.start(static_cast(2 * std::thread::hardware_concurrency())); + auto thd_start = [&](const char *info) { + std::clog << "thread start: " << info << std::endl; + }; + + // db_config 初始化 + nanodbc::connection conn = nanodbc::connection(db_dsn, db_name, db_passwd); + + //发送负载情况(Task2) + this->pool_.run([this]() { update_data_info(); }); + thd_start("update data info"); +// +// //更新数据缓存(Task3) +// this->pool_.run([this]() { update_clis_data(); }); +// thd_start("update clients data"); + + //读取配置文件(Task4) + this->pool_.run([this]() { read_config(); }); + thd_start("read config"); + + //清空(Task5) + this->pool_.run([this]() { clear_cli_data(); }); + thd_start("clear cli data"); + + //TCP相关(Task6) + this->listen_cli_beat(); + thd_start("listen client beat") + //输出日志 +} + + +void Mirror::update_data_info() { +// 发送ip地址 +// using Server::IP; + + // 更新间隔 + size_t time = 0; + + unsigned char this_ip[4] = "0000";//解析ip + + // 发送的息 + char send_buf[8] = {0}; +// 定义计算服务器负载情况的函数 + auto cal_ser_load = [&]() -> uint8_t { + return '0'; + }; + +// 定义计算内存负载情况的函数 + auto cal_mem_load = [&]() -> uint8_t { + std::ifstream in; + std::string filename = ""; + return '0'; + }; + +// 定义计算网络负载情况的函数 + auto cal_net_load = [&]() -> uint8_t { + return '0'; + }; + + auto get_packet = [&]() { + +// getMyip + std::string host; + std::string ip; + bool ret = GetHostInfo(host, ip); + if (!ret) { + //报错 + } + IP this_ip(ip); + + //calculate ServerLoad + unsigned char serverLoad = cal_ser_load(); + + // DtlLoadState.serve_load = serverLoad; + //calculate MemoryLoad + unsigned char memLoad = cal_mem_load(); +// DtlLoadState.mem_load = memLoad; + //calculate NetworkLoad + unsigned char netLoad = cal_net_load(); +// DtlLoadState.net_load_ = netLoad; + +//this_ip + std::vector ret{}; + ret.push_back(this_ip.seg0); + ret.push_back(this_ip.seg1); + ret.push_back(this_ip.seg2); + ret.push_back(this_ip.seg3); + ret.push_back(serverLoad); //服务器负载 + ret.push_back(memLoad); //内存负载 + ret.push_back(netLoad); //网络负载 + ret.push_back('\0'); + return ret; + }; + + //重置缓冲 + memset(send_buf, 0, sizeof(send_buf)); + + //获取负载情况 + std::vector info = get_packet(); + + //更新负载情况 + for (int i = 0; i < 7; i++) + send_buf[i] = info[i]; + + //最后位填充0 + send_buf[7] = '\0'; + + //重置time + time = 1; + + +//线程主循环 + while (true) { + + if (time == telemeter::setting->mir_load_report_interval_) { + //to_string(8byte) = 4+1+1+1+1 true/false + //重置缓冲 + memset(send_buf, 0, sizeof(send_buf)); + + //获取负载情况 + std::vector info = get_packet(); + + //更新负载情况 + for (int i = 0; i < 7; i++) + send_buf[i] = info[i]; + + //最后位填充0 + send_buf[7] = '\0'; + + //重置time + time = 1; + } + +// 发送‘心跳包’ + int sock; + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + std::cerr << "sock error" << std::endl; + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; +// 设置发送端口 + servaddr.sin_port = htons(port::kMIR_BEAT_); +// 设置发送ip +/*修改:若发送失败,则沿用之前的ip*/ + servaddr.sin_addr.s_addr = inet_addr(setting->center_ip_); +// 发送缓存 + sendto(sock, send_buf, strlen(send_buf), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); + // 统计发送心跳包次数 + time++; + //心跳包频率 + sleep(telemeter::setting->mir_heart_beat_interval_ * 1000); + } +} + + +//定时拉取数据库信息, 更新时间戳 +//暂停该函数 +/* +void Mirror::update_clis_data() { + //cli-classinfo缓存 + std::unordered_map clis_data; + +// 校园日历 + scu_date sD{1, 1}; + scu_date sD_1{1, 1}; + scu_date *scuDate = &sD; + scu_date *scuDate_copy = &sD_1; + + scu_date scuDate_cache{}; + + scu_time nowTime{0, 0}; + + auto swap_scu_date_ptr = [&]() { + scu_date *tmp = scuDate; + scuDate_copy = scuDate; + scuDate = tmp; + }; + +//写当日date(其实不会出现冲突.但为以后消费者模型做准备工作) + auto update_scu_date = [&]() { +//更新当日上课信息 + db_control::check_week_and_day(conn, scuDate_cache); +//复制至副本 + memcpy(scuDate_copy, &scuDate_cache, sizeof(scu_date)); +//交换指针 + swap_scu_date_ptr(); + }; + +// 判断时间 + auto at_middle = [&](const scu_time &lTime, const scu_time &rTime) { + return (lTime <= nowTime) && (nowTime < rTime); + }; + + auto get_seconds_from_now = [&](const scu_time &time) { + nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + + auto query_scu_time = [&](int &xqh, int &jc) -> scu_time { +// 获取迭代器,遍历时间表 + + auto iter1 = this->wj_Time.begin(); + auto iter2 = this->ja_Time.begin(); +// 上课节次,用于返回 + int skjc = 0; + + nowTime = scu_time::toScutime(muduo::Timestamp::now());//获取当前时间,进行分析 + + for (; iter1 != wj_Time.end(); iter1++, iter2++) { + skjc++; + jc = skjc; + if (skjc <= 4) { + if (nowTime <= *iter1) { + xqh = 1; + return scu_time(0, 15); + } else { + if (nowTime <= *iter2) { + xqh = 3; + if (skjc == 4) + return scu_time(2, 40); + else + return scu_time(0, 40); + } else { + continue; + } + } + } else { + if (nowTime <= *iter2) { + xqh = 3; + return scu_time(0, 10); + } else { + if (nowTime <= *iter1) { + xqh = 1; + if (skjc == 9) //晚餐 + return scu_time(1, 30); + else if (skjc == 7) + return scu_time(0, 55); + else if (skjc == 12) + return scu_time(0, 0); + else + return scu_time(0, 45); + } else { + continue; + } + } + } + } + return scu_time::toScutime(muduo::Timestamp::now()); + }; + + +// 自动计算当前时间 + auto query_clis_data = [&, this]() { + std::unordered_map clis_data_cache_; + bool two_lessons = true; + int xqh = 0; //校区号 + int jc = 0; //时间 + + auto update_uC_map = [](const std::unordered_map &data_map, + std::unordered_map *origin_map, + std::unordered_map *copy_map) { + //赋值 + *copy_map = data_map; +// 交换指针 + auto tmp = copy_map; + copy_map = origin_map; + origin_map = tmp; + }; + + + //获取应当更新的校区号与节次 + scu_time wait_time = query_scu_time(xqh, jc); + + if (jc == 4 || jc == 9 || jc == 12) + two_lessons = false; + size_t wait_second = wait_time.toSeconds(); + if (xqh == 1) { +// 更新值 +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + clis_data_cache_ = *(this->wj_clis_data_); +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); +// 获取当前时间戳 + muduo::Timestamp nTime = muduo::Timestamp::now(); +// 更新时间戳 + update_timestamp(nTime, wj_timestamp_, wj_timestamp_copy); + // 交换指针 + + update_uC_map(clis_data_cache_, this->wj_clis_data_, this->wj_clis_data_copy); + } else if (xqh == 3) { +// 更新值 + clis_data_cache_ = *ja_clis_data_; +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); +// 获取当前时间戳 + muduo::Timestamp nTime = muduo::Timestamp::now(); +// 更新时间戳 + update_timestamp(nTime, ja_timestamp_, ja_timestamp_copy); +// 交换指针 + update_uC_map(clis_data_cache_, this->ja_clis_data_, this->ja_clis_data_copy); + } + + return wait_second; + }; + +// mirror开机时,初始化当时时间 + update_scu_date(); + muduo::Timestamp nTime = muduo::Timestamp::now(); + nowTime = scu_time::toScutime(nTime); + + +// 进入任务线程阶段 + while (true) { +// 挂起. 7.55唤醒 + sleep(get_seconds_from_now(scu_time(7, 55)) * 1000); + + while (true) { + nowTime = scu_time::toScutime(muduo::Timestamp::now());//记录当前时间 + size_t sleepSeconds = 0; + sleepSeconds = query_clis_data(); //更新数据,在函数体内自动计算时间 + + if (sleepSeconds == 0) + break; + //休眠至下一次更新 + sleep(sleepSeconds * 1000); + } + sleep(get_seconds_from_now(scu_time(24, 0)) * 1000); //沉睡至24点 +// 24点更新当日上课信息 + update_scu_date(); + } + + +} +*/ + +//读取配置文件 +/*待更改*/ +void Mirror::read_config() { + +// 后可以考虑使用json格式 + static std::string config_file_path{"MirrorConfig.txt"}; + static std::ifstream in{config_file_path, std::ios::in}; + Setting set{}; + memset(&set, 0, sizeof(Setting)); + size_t next_read_interval{0}; + + auto read_data = [&]() { + if (!in.is_open()) + in.open(config_file_path, std::ios::in); + std::string line{}; + while (in.good()) { + std::getline(in, line, '\n'); + if (line.size() < 2 || line.front() == '/') + continue; + else if (line.find("next_read") != std::string::npos) + next_read_interval = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if (line.find("mir_heart") != std::string::npos) + set.mir_heart_beat_interval_ = std::stoi( + std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if (line.find("mir_load") != std::string::npos) + set.mir_load_report_interval_ = std::stoi( + std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + else if (line.find("cli_class") != std::string::npos) + set.cli_class_info_cache_time_ = std::stoi( + std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + } + }; + + + auto swap = [](Setting *src, Setting *dst) { + Setting *tmp = dst; + dst = src; + src = tmp; + }; + + //主任务 + while (true) { + //读取配置文件 + read_data(); + + //复制到配置副本中 + memcpy(telemeter::setting_copy, &set, sizeof(Setting)); + + //交换主副配置指针 + swap(telemeter::setting_copy, telemeter::setting); //atomic operation + + //挂起该进程 + sleep(next_read_interval * 1000); + } +} + +//清除mirror->client树信息 +void Mirror::clear_cli_data() { + auto update_uC_map = [](const std::unordered_map &data_map, + std::unordered_map *origin_map, + std::unordered_map *copy_map) { + //赋值 + *copy_map = data_map; +// 交换指针 + auto tmp = copy_map; + copy_map = origin_map; + origin_map = tmp; + }; + auto get_seconds_from_now = [&](const scu_time &time) { + nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + while (true) { + std::unordered_map newmap; + update_uC_map(newmap, wj_clis_data, wj_clis_data_copy); + update_uC_map(newmap, ja_clis_data, ja_clis_data_copy); + + //配置文件读取upload,time + sleep(get_seconds_from_now(scu_time(24, 0)) * 1000); + //每日24时更新 + } +} + +void Mirror::update_pictures_info() { + //while true + auto swap = []() { + + }; + + while (true) { + //查询数据库 + + std::vector backgrounds; + + db_control::query_background(conn, backgrounds); + //图片信息与 + //数据 + //循环 + for (auto iter = backgorunds->begin(); iter != backgorunds->end(); iter++) { + //解码 + 储存图片 + //路径 + std::string path = this.img_path + "/" + std::to_string(iter->PicId) + ".jpg"; + + codec::downPic(path, iter->PicCode); + } + + sleep(setting->update_pic_interval * 60 * 60 * 1000) + } + +} + +//多并发 +void Mirror::listen_cli_beat() { + muduo::net::EventLoop loop_; + muduo::net::TcpServer server_(&loop_, muduo::net::InetAddress(port::kCLI_BEAT_), ""); + //set server.onConnect 连接函数 + server_.setMessageCallback(&Mirror::on_message); + server_.start(); + loop_.loop(); +} + +//更新参数, 如Scu_date与scu_time->skjc + + +//待修改 +void Mirror::on_message(const muduo::net::TcpConnectionPtr &connectionPtr, + muduo::net::Buffer *msg, + muduo::Timestamp time) { + std::string src = msg->retrieveAsString(); + Cli::Uuid id; + std::string timeStamp; + getIdAndStamp(src, id, timeStamp); + + //查找到旧数据的哈希值 + if (this->cli_info_.find(id) != this->cli_info_.end()) { + OldHash old = this->cli_info_[id]; + } else { + OldHash temp_hush{0, 0, 0, 0}; + this->cli_info_.insert(std::pair(id, temp_hush)); + } + + //去数据库中查询新数据 + std::string now_stamp = muduo::Timestamp::now().toString(); + //分析当前的时间戳 + unsigned long stamp = std::stoul(now_stamp); + stamp -= 8 * 60 * 60;//(UTC+8h) + + int course_section; + if (Class2Campus.find(id) == Class2Campus.end()) { + CliDes new_des; + new_des.id = id; + new_des.campus = find_campus; + new_des.stamp = now_stamp; + Class2Campus.insert(std::pair(id, new_des)); + } + + if (Class2Campus[id].campus == 3) { //江安校区 + course_section = this->ja_section; + } else { + couse_section = this->wj_section; + } + + bool next_event = true; + if (course_section == 4 || course_section == 9 || course_section == 12) + next_event = false; + + std::string pic_url = db_control::find_pic(this->conn, id, now_stamp); + std::deque msg = db_control::find_mes(this->conn, id, std::to_string(stamp)); //统一utc时间 + Lesson lesson_1 = db_control::find_lesson(this->conn, id, course_section, this->week, this->day); + Lesson lesson_2; + if (next_event) { + lesson_2 = db_control::find_lesson(this->conn, id, course_section + 1, this->week, this->day); + } + OldHash new_hash{ + std::hash()(pic_url), + std::hash < std::deque < std::string >> ()(msg), + std::hash()(lesson_1), + //这里next_event暂时不知道从哪个数据中哈希, 置为0 + std::hash()(lesson_2) + }; + + if (new_hash == old) + conn->send(json_control::no_need_update); + else { + ClassMes sendInfo; + sendInfo.img_url = pic_url; + sendInfo.messages = msg; + sendInfo.lesson_1 = lesson_1; + sendInfo.lesson_2 = lesson_2; + std::string info = json_lib::getJsonInfo(sendInfo, now_stamp); + conn->send(info); + } + +} + + +void Mirror::update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, + muduo::Timestamp *copy_campus_stamp) { + + // 赋值 + *copy_campus_stamp = dataStamp; + +// 交换指针 + auto swap = [](muduo::Timestamp *origin, muduo::Timestamp *copy) { + muduo::Timestamp *tmp = origin; + origin = copy; + copy = tmp; + }; + swap(origin_campus_stamp, copy_campus_stamp); +} diff --git a/Src/Mirror/MirrorMain.cpp b/Src/Mirror/MirrorMain.cpp new file mode 100644 index 0000000..af3b86c --- /dev/null +++ b/Src/Mirror/MirrorMain.cpp @@ -0,0 +1,18 @@ +#include + +#include "Mirror.cpp" + +int main() +{ + static const char* crush_log = "../crush.txt"; + + Mirror mir; + try + { + mir.start(); + } + catch(std::exception& e) + { + std::cerr << e.what() << '\n'; + } +} diff --git a/Src/Mirror/codec_lib.cpp b/Src/Mirror/codec_lib.cpp new file mode 100644 index 0000000..dfe0dc0 --- /dev/null +++ b/Src/Mirror/codec_lib.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +namespace codec { + using base64 = cppcodec::base64_rfc4648; + + void downPic(const std::string &code, const std::string &path) { + //打开文件 + std::ofstream ofs(path, std::ios::trunc | std::ios::binary); + //异常处理 + if (!ofs) { + exit(-1); + } + //解码 + std::vector buff = base64::decode(code); + //写入文件 + ofs.write(reinterpret_cast(buff.data()), buff.size()); + //关闭文件 + ofs.close(); + } + +} \ No newline at end of file diff --git a/Src/Mirror/db_lib.cpp b/Src/Mirror/db_lib.cpp new file mode 100644 index 0000000..4fd9602 --- /dev/null +++ b/Src/Mirror/db_lib.cpp @@ -0,0 +1,152 @@ +#include +#include + +namespace db_control { + + using Cli::Uuid; + + void check_week_and_day(nanodbc::connection conn, scu_date &date) { + if (date.day == 7) { + date.week += 1; + date.day = 1; + } else { + date.day += 1; + } + } + + /* + * param CCmap uuid->ClassMes + * param skjc 上课节次 + * + */ + + void + query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, + scu_date *date, Uuid id) { + size_t week = date->week; //第几周 + size_t day = date->day; //星期几 + bool new_client = false; + std::string find_stmt{}; + + std::string uuid_stmt{}; + + if (id < 0) { + auto iter = CCmap.begin(); + uuid_stmt += "( U.uuid = " + std::to_string(iter->first); + for (auto iter = CCmap.begin(); iter != CCmap.end(); iter++) { + uuid_stmt += " OR\n U.uuid = "; + uuid_stmt += std::to_string(iter->first); + } + uuid_stmt += ") AND\n"; + } else { + uuid_stmt = std::string("U.uuid = " + std::to_string(id)); + new_client = true; + } + auto get_find_stmt = [&](size_t skJc) { + find_stmt = std::string(std::string("SELECT\n" + "U.uuid AS uuid,\n" + "P.kch AS `kch`,\n" + "P.kxh AS `kxh`,\n" + "K.kcm AS `kcm`,\n" + "P.jsxm AS `jsxm`,\n" + "P.jxdd AS `jdxx`,\n" + "p.jsszxqh AS `jsszxqh`\n" + "FROM\n" + "uuid_jxdd AS U\n" + "INNER JOIN pksj AS P ON U.jxdd = P.jxdd AND U.jsszxqh = P.jsszxqh\n" + "INNER JOIN kcb AS K ON P.kch = K.kch\n" + "WHERE\n") + + uuid_stmt + + "P.sksj <= " + std::to_string(skJc) + " AND\n" + "P.sksj+P.cxjc\t >= " + std::to_string(skJc) + + " AND\n" + + "P.skxq = " + std::to_string(day) + " AND\n" + + "SUBSTR(qsz," + + std::to_string(week) + ",1)=\'1\'"); + }; + + auto update_map = [&](size_t jc, bool first, bool new_cli = false) { + get_find_stmt(skjc); + try { + nanodbc::result find_row = nanodbc::execute(conn, find_stmt); + for (; find_row.next();) { + int uid = find_row.get(0); + + if (new_cli) { + int xqh = find_row.get(6); + std::string dd = find_row.get(5); + ClassPlace cp; + cp.jxdd_ = dd; + cp.jsszxqh = xqh; + ClassMes ci; + ci.classPlace_ = cp; + CCmap.insert(std::make_pair(id, ci)); + } + + if (CCmap.find(uid) != CCmap.end()) { + Lesson les = Lesson(find_row.get(1), find_row.get(2), + find_row.get(3), find_row.get(4), + find_row.get(5)); + if (first) + CCmap.at(uid).lesson_1 = les; + else + CCmap.at(uid).lesson_2 = les; + } else { + continue; + } + } + } catch (const std::exception &e) { + std::cerr << e.what() << std::endl; //更换为日志报错 + } + }; + +// 更新当前节次 + update_map(skjc, true, new_client); + if (two_lesson) { +// 更新下一节次 + update_map(skjc + 1, false, new_client); + } + + } + + void query_background(nanodbc::connection conn, std::vector &backgrounds) { + //查询所有 + std::string sel_stmt = "SELECT * FROM backgrounds"; + //执行语句 + nanodbc::result find_row = nanodbc::execute(conn, sel_stmt); + + for (; sel_stmt.next();) { + int id = sel_stmt.get(0); + std::string code = sel_stmt.get(1); + std::string des = sel_stmt.get(2); + + backgrounds.emplace_back(id, code, des); + } + } + + std::string find_pic(const nanodbc::connection &conn, Cli::Uuid id) { + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, std::string("SELECT background FROM places WHERE UUID = ?")); + + statement.bind(0, std::to_string(id)); + + nanodbc::result row = nanodbc.execute(statement); + + while (row.next()) { + return row.get(0); + } + } + + + Lesson find_event(const nanodbc::connection &conn, Cli::Uuid id, nanodbc::connection conn, size_t skjc, scu_date *date, Uuid id){ + + } + + std::deque find_message(const nanodbc::connection& conn, Cli::Uuid id, muduo::Timestamp &stamp){ + + } + + + +} diff --git a/Src/Mirror/json_lib.cpp b/Src/Mirror/json_lib.cpp new file mode 100644 index 0000000..3305847 --- /dev/null +++ b/Src/Mirror/json_lib.cpp @@ -0,0 +1,120 @@ +#include + +namespace json_control { + + std::string no_need_update = "{\"needUpdate\":false}"; + + void getJson(rapidjson::Writer &writer, const Message &mes) { + //开启对象 + writer.StartObject(); + //title + writer.Key("Title"); + writer.String(mes.title.c_str()); + + //text + writer.Key("text"); + writer.String(mes.text.c_str()); + + //expiretime + writer.Key("expireTime"); + writer.Int(mes.expireTime); + + //结束对象 + writer.EndObject(); + } + + void getJson(rapidjson::Writer &writer, const Lesson &les) { + //开始对象 + writer.StartObject(); + + //课程号 + writer.Key("kch"); + writer.String(les.kch_.c_str()); + + //课序号 + writer.Key("kxh"); + writer.Int(les.kxh_); + + //课程名 + writer.Key("kcm"); + writer.String(les.kcm_.c_str()); + + //教师姓名 + writer.Key("jsxm"); + writer.String(les.jsxm_.c_str()); + + //教学地点 + writer.Key("jxdd"); + writer.String(les.jxdd_.c_str()); + + //结束对象 + writer.EndObject(); + } + + std::string getJsonInfo(const ClassMes &mes, const muduo::Timestamp ×tamp) { + rapidjson::StringBuffer strBuf; + rapidjson::Writer writer(strBuf); + //声明strBuf与writer对象 + + //开启json对象 + writer.StartObject(); + + //时间戳 + writer.Key("time"); + writer.String(timestamp.toString().c_str()); + + //图像的url + writer.Key("image_url"); + writer.String(mes.image_url.c_str()); + + //消息队列 + writer.Key("message"); + //开启数组 + writer.StartArray(); + for (auto iter = mes.messages.begin(); iter != mes.messages.end(); iter++) { + getJson(writer, *iter); + } + //结束数组 + writer.EndArray(); + + //第一节课信息 + writer.Key("event"); + + getJson(writer, mes.lesson_1); + + //第二节课信息 + writer.Key("next_event"); + + getJson(writer, mes.lesson_2); + + //需要更新 + writer.Key("needUpdate"); + writer.Bool(true); + + //结束json对象 + writer.EndObject(); + + std::string json = strBuf.GetString(); + + return json; + } + + void getIdAndStamp(const std::string &src, Cli::Uuid &id, std::string &stamp) { + +// 解析document + rapidjson::Document document; + document.Parse(src.c_str()); + +// 分析获取id和stamp + rapidjson::Value::ConstMemberIterator iter = document.FindMember("UUID"); + if (iter != document.MemberEnd()) { + id = std::stoi(iter->value.GetString()); + } + + iter = document.FindMember("time"); + if (iter != document.MemberEnd()) { + stamp = iter->value.GetString(); + } + + } +}//End namespace of json_control diff --git a/cmake-build-debug/CMakeFiles/clion-log.txt b/cmake-build-debug/CMakeFiles/clion-log.txt index 9935687..8d31f15 100644 --- a/cmake-build-debug/CMakeFiles/clion-log.txt +++ b/cmake-build-debug/CMakeFiles/clion-log.txt @@ -1,32 +1,4 @@ C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -DCMAKE_BUILD_TYPE=Debug -G "CodeBlocks - MinGW Makefiles" D:\2021_2\cids-server --- The C compiler identification is GNU 8.1.0 --- The CXX compiler identification is GNU 8.1.0 --- Detecting C compiler ABI info --- Detecting C compiler ABI info - done --- Check for working C compiler: C:/BC/C/mingw64/bin/gcc.exe - skipped --- Detecting C compile features --- Detecting C compile features - done --- Detecting CXX compiler ABI info --- Detecting CXX compiler ABI info - done --- Check for working CXX compiler: C:/BC/C/mingw64/bin/g++.exe - skipped --- Detecting CXX compile features --- Detecting CXX compile features - done -CMake Error at CMakeLists.txt:6 (find_package): - By not providing "FindRapidJSON.cmake" in CMAKE_MODULE_PATH this project - has asked CMake to find a package configuration file provided by - "RapidJSON", but CMake did not find one. - - Could not find a package configuration file provided by "RapidJSON" with - any of the following names: - - RapidJSONConfig.cmake - rapidjson-config.cmake - - Add the installation prefix of "RapidJSON" to CMAKE_PREFIX_PATH or set - "RapidJSON_DIR" to a directory containing one of the above files. If - "RapidJSON" provides a separate development package or SDK, be sure it has - been installed. - - --- Configuring incomplete, errors occurred! -See also "D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeOutput.log". +-- Configuring done +-- Generating done +-- Build files have been written to: D:/2021_2/cids-server/cmake-build-debug diff --git a/include/Common/ServerBase.hpp b/include/Common/ServerBase.hpp new file mode 100644 index 0000000..70e45db --- /dev/null +++ b/include/Common/ServerBase.hpp @@ -0,0 +1,45 @@ +// +// Created by XM on 2021/5/18. +// + +#ifndef PRO_SERVERBASE_HPP +#define PRO_SERVERBASE_HPP + +#pragma once + +#include + +struct scu_date { + size_t week; + size_t day; +}; + +class scu_time { + +private: + size_t hour; + size_t minute; + +public: + + scu_time(size_t h, size_t m) : hour(h), minute(m) {} + + scu_time(const scu_time &that) : hour(that.hour), minute(that.minute) {} + + scu_time operator-(const scu_time &rhs) const; + + bool operator<(const scu_time& rhs) const; + + bool operator=(const scu_time &rhs); + + bool operator<=(const scu_time &rhs) const; + + unsigned toSeconds(); + + static scu_time toScutime(const muduo::Timestamp ×tamp) ; + + +}; + + +#endif //PRO_SERVERBASE_HPP diff --git a/include/Common/Telemeter.hpp b/include/Common/Telemeter.hpp new file mode 100644 index 0000000..a66c500 --- /dev/null +++ b/include/Common/Telemeter.hpp @@ -0,0 +1,121 @@ +#ifndef SRC_TELEMETER_H +#define SRC_TELEMETER_H + +#pragma once + +#include + +#include +#include + +enum class LoadLevel : uint8_t { + untapped = 0, //no client dispatched on this mirror + light = 1, //[0% - 50%] + medium = 2, //[50% - 80%] + heavy = 3, //[ >= 80%] +}; + +static std::string tostring(LoadLevel ll) { + switch (ll) { + case LoadLevel::untapped: + return "untapped"; + case LoadLevel::light: + return "light"; + case LoadLevel::medium: + return "medium"; + case LoadLevel::heavy: + return "heavy"; + default: + return "undefined"; + } +} + + +//POD type +struct DetailLoadState { + uint8_t mem_load, serve_load, net_load_, reserve_seg_; +}; + +#ifdef SRC_CENTER_H +//center的setting, POD type +struct Setting +{ + uint mir_load_record_interval_; //记录mirror负载到缓存的间隔(按照心跳包的个数来计数), 从配置文件中读 + uint mir_dblog_interval_; //将mirror负载缓存更新到数据库(数据文件)的间隔(缓存了这么多之后打一次log), 从配置文件中读 + uint mir_max_disbeat_time_; //多少个心跳轮无心跳视为断线 + uint cli_login_cache_time_; //清空一个cli登录缓冲的时间 + uint load_balance_interval_; //多少个cli启动后运行一次负载均衡调度算法 + uint clear_mirs_data_time_; //自0点开始何时清空一次mir_data中的信息 + //unsigned long reserve_seg_; //保留段 +}; +//第一字段为60表示一分钟(60个心跳包)记录一次mir的负载情况, +//第二字段为5表示5分钟(缓存5次)输出到遥测数据库一次 + +const constexpr uint _permanent_thread_num_ = 4U; //center的常驻线程数量 + +#endif + +#ifdef SRC_MIRROR_H +//mirror的setting, POD type +struct Setting +{ + std::string center_ip_; //?解析 +// int backup_center_ip_; + int next_read_interval_; + uint8_t mir_heart_beat_interval_; + uint16_t mir_load_report_interval_; + uint16_t cli_class_info_cache_time_; + //数据库ip? +}; +#endif + +#define RESERVE_SEGMENG_INIT_VALUE 0U + +namespace telemeter { + const constexpr char *klog_file = "TelemeterLog.txt"; //临时的遥测日志文件 + +#ifdef SRC_CENTER_H + //双缓冲配置表解决一写多读线程安全问题 + + static Setting _set_cache_one = {60, 5, 15, 60, 20, 0}; + static Setting _set_cache_two = {60, 5, 15, 60, 20, 0}; + //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 + static Setting* setting = &_set_cache_one; + static Setting* setting_copy = &_set_cache_two; + + //将配置信息返回成一个字符串输出 + // static auto settting_info = [](Setting* set = telemeter::setting) -> std::string + // { + // return fmt::format("mir load record interval: -{0}\n \ + // nmir database log interval: -{1}\n \ + // mir max disbeat time: -{2}\n \ + // cli login cache time: -{3}\n \ + // load balance interval: -{4}\n \ + // clear mirs data time: -{5}", + // set->mir_load_record_interval_, + // set->mir_dblog_interval_, + // set->mir_max_disbeat_time_, + // set->cli_login_cache_time_, + // set->load_balance_interval_, + // set->clear_mirs_data_time_); + // }; +#endif + +#ifdef SRC_MIRROR_H + static Setting _set_cache_one = {0,600,1,60,600}; + static Setting _set_cache_two = {0,600,1,60,600}; + //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 + static Setting* setting = &_set_cache_one; + static Setting* setting_copy = &_set_cache_two; + +#endif + //获取本机负载情况的函数, 需要统计空闲内存占比, cpu负载, 空闲磁盘占比 + //LoadLevel getLocalLoadLevel(); + + //int getLocalMemLoad(); + //int getLocalSevLoad(); + //int getLocalNetLoad(); +} + + +#endif //SRC_TELEMETER_H \ No newline at end of file diff --git a/include/Common/Udp.hpp b/include/Common/Udp.hpp new file mode 100644 index 0000000..56dcb0f --- /dev/null +++ b/include/Common/Udp.hpp @@ -0,0 +1,90 @@ +#ifndef SRC_UDP_H +#define SRC_UDP_H + +#pragma once + +#include +#include +#include +#include +#include +#include /* struct hostent */ +#include +#include +#include +#include +#include +#include + +//暂时以int表示ip, 有需要则封装成类 +using IP = int; + +namespace port +{ + const constexpr size_t kCLI_LOGIN_ = 20800; + const constexpr size_t kCLI_BEAT_ = 20801; + const constexpr size_t kMIR_BEAT_ = 20802; + const constexpr size_t kINS_MSG_ = 20803; +} + +namespace protocal +{ + //以字节计算的每个包的大小和协议中每一部分的大小, 二级缩进的和应该等于第一级缩进 + const constexpr size_t kCLI_LOGIN_PACSIZE_ = 8; + const constexpr size_t kCLI_LOGIN_UID_ = 7; + const constexpr size_t kCLI_LOGIN_STATE_ = 1; + + const constexpr size_t kCENT_RESPONSE_PACSIZE_ = 4; + + const constexpr size_t kMIR_BEAT_PACSIZE_ = 8; + const constexpr size_t kMIR_BEAT_IP_ = 4; + const constexpr size_t kMIR_BEAT_LOAD_ = 4; +} + +struct IP { + unsigned char seg0; + unsigned char seg1; + unsigned char seg2; + unsigned char seg3; + + IP(int i0 = 0, int i1 = 0, int i2 = 0, int i3 = 0) : seg0(i0), seg1(i1), seg2(i2), seg3(i3) {}; + + IP(std::string addr) { + std::istringstream iss(addr); + std::string buffer; + std::vector res; + while (std::getline(iss, buffer, '.')) { + res.push_back((unsigned char) (std::stoi(buffer))); + } + if (res.size() != 4) { + //异常 + } + this->seg0 = res[0]; + this->seg1 = res[1]; + this->seg2 = res[2]; + this->seg3 = res[3]; + } +}; + +bool GetHostInfo(std::string& hostName, std::string& Ip) { + char name[256]; + gethostname(name, sizeof(name)); + hostName = name; + + struct hostent* host = gethostbyname(name); + char ipStr[32]; + const char* ret = inet_ntop(host->h_addrtype, host->h_addr_list[0], ipStr, sizeof(ipStr)); + if (NULL==ret) { + std::cout << "hostname transform to ip failed"; + return false; + } + Ip = ipStr; + return true; +} + + + + +#endif //SRC_UDP_H + + diff --git a/include/ServerBase.cpp b/include/ServerBase.cpp new file mode 100644 index 0000000..5d2f2ea --- /dev/null +++ b/include/ServerBase.cpp @@ -0,0 +1,57 @@ +#include + +bool scu_time::operator=(const scu_time &rhs) { + return this->hour == rhs.hour && this->minute == rhs.minute; +} + +scu_time scu_time::operator-(const scu_time &rhs) const{ + if (*this < rhs) + size_t lMinute = (this->hour + 24) * 60 + this->minute; + else + size_t lMinute = this->hour * 60 + this->minute; + size_t rMinute = rhs.hour * 60 + rhs.minute; + size_t nHour = (lMinute - rMinute) % 60; + size_t nMinute = (lMinute - rMinute) - nHour * 60; + return scu_time(nHour, nMinute); +} + +bool scu_time::operator<(const scu_time &rhs) const { + if (this->hour > rhs.hour) { + return false; + } else { + if (this->minute >= rhs.minute) { + return false; + } else { + return true; + } + } +} + +bool scu_time::operator<=(const scu_time &rhs) const { + if (this->hour > rhs.hour) { + return false; + } else { + if (this->minute > rhs.minute) + return false; + else + return true; + } +} + +unsigned scu_time::toSeconds() { + return this->hour * 3600 + this->minute * 60; +} + +scu_time scu_time::toScutime(const muduo::Timestamp ×tamp){ + long allSeconds = std::stol(timestamp.toString()); + int seconds = allSeconds % 86400; + size_t hour = seconds / 3600; + size_t minute = (seconds - hour * 3600) / 60; + if(hour >= 16) + hour -= 16; + else + hour += 8; + return scu_time(hour, minute); +} + + diff --git a/include/ServerBase.hpp b/include/ServerBase.hpp new file mode 100644 index 0000000..70e45db --- /dev/null +++ b/include/ServerBase.hpp @@ -0,0 +1,45 @@ +// +// Created by XM on 2021/5/18. +// + +#ifndef PRO_SERVERBASE_HPP +#define PRO_SERVERBASE_HPP + +#pragma once + +#include + +struct scu_date { + size_t week; + size_t day; +}; + +class scu_time { + +private: + size_t hour; + size_t minute; + +public: + + scu_time(size_t h, size_t m) : hour(h), minute(m) {} + + scu_time(const scu_time &that) : hour(that.hour), minute(that.minute) {} + + scu_time operator-(const scu_time &rhs) const; + + bool operator<(const scu_time& rhs) const; + + bool operator=(const scu_time &rhs); + + bool operator<=(const scu_time &rhs) const; + + unsigned toSeconds(); + + static scu_time toScutime(const muduo::Timestamp ×tamp) ; + + +}; + + +#endif //PRO_SERVERBASE_HPP diff --git a/include/Telemeter.hpp b/include/Telemeter.hpp index f9b34ff..3a4c876 100644 --- a/include/Telemeter.hpp +++ b/include/Telemeter.hpp @@ -3,40 +3,54 @@ #pragma once +#include "fmt/core.h" + #include #include enum class LoadLevel : uint8_t { - untapped = 0, //no client dispatched on this mirror - light = 1, //[0% - 50%] - medium = 2, //[50% - 80%] - heavy = 3, //[ >= 80%] + untapped = 0, //no client dispatched on this mirror + light = 1, //[0% - 50%] + medium = 2, //[50% - 80%] + heavy = 3, //[ >= 80%] }; +static std::string tostring(LoadLevel ll) +{ + switch (ll) + { + case LoadLevel::untapped: return "untapped"; + case LoadLevel::light: return "light"; + case LoadLevel::medium: return "medium"; + case LoadLevel::heavy: return "heavy"; + default: return "undefined"; + } +} + //POD type struct DetailLoadState { - uint8_t mem_load, serve_load, net_load_, reserve_seg_; + uint8_t mem_load, serve_load, net_load_, reserve_seg_; }; -void copy(DetailLoadState* dest, const DetailLoadState* sour) -{ memcpy(dest, sour, sizeof(DetailLoadState)); } - #ifdef SRC_CENTER_H //center的setting, POD type struct Setting { - uint8_t mir_load_record_interval_; //记录mirror负载到缓存的间隔(按照心跳包的个数来计数), 从配置文件中读 - uint8_t mir_dblog_interval_; //将mirror负载缓存更新到数据库(数据文件)的间隔(缓存了这么多之后打一次log), 从配置文件中读 - uint8_t mir_max_disbeat_time_; //多少个心跳轮无心跳视为断线 - uint8_t cli_login_cache_time_; //清空一个cli登录缓冲的时间 + uint mir_load_record_interval_; //记录mirror负载到缓存的间隔(按照心跳包的个数来计数), 从配置文件中读 + uint mir_dblog_interval_; //将mirror负载缓存更新到数据库(数据文件)的间隔(缓存了这么多之后打一次log), 从配置文件中读 + uint mir_max_disbeat_time_; //多少个心跳轮无心跳视为断线 + uint cli_login_cache_time_; //清空一个cli登录缓冲的时间 + uint load_balance_interval_; //多少个cli启动后运行一次负载均衡调度算法 + uint clear_mirs_data_time_; //自0点开始何时清空一次mir_data中的信息 + //unsigned long reserve_seg_; //保留段 }; -//第一字段为60表示一分钟(60个心跳包)记录一次mir的负载情况, +//第一字段为60表示一分钟(60个心跳包)记录一次mir的负载情况, //第二字段为5表示5分钟(缓存5次)输出到遥测数据库一次 -const constexpr uint _permanent_thread_num_ = 3; //center的常驻线程数量 +const constexpr uint _permanent_thread_num_ = 4U; //center的常驻线程数量 #endif @@ -44,48 +58,55 @@ const constexpr uint _permanent_thread_num_ = 3; //center的常驻线程数量 //mirror的setting, POD type struct Setting { - uint8_t mir_beat_interval_; - uint8_t mir_report_interval_; - uint8_t class_cache_time_; - uint8_t class_interval_; + int center_ip_; + //int backup_center_ip_; + uint8_t mir_beat_interval_; + uint8_t //数据库ip? }; - #endif -#define RESERVE_SEGMENG_INIT_VALUE 0 +#define RESERVE_SEGMENG_INIT_VALUE 0U namespace telemeter { - const constexpr char* klog_file = "TelemeterLog.txt"; //临时的遥测日志文件 - + const constexpr char* klog_file = "TelemeterLog.txt"; //临时的遥测日志文件 + #ifdef SRC_CENTER_H - //双缓冲配置表解决一写多读线程安全问题 - Setting _set_cache_one = {60, 5, 15, 60}; - Setting _set_cache_two = {60, 5, 15, 60}; + //双缓冲配置表解决一写多读线程安全问题 + static Setting _set_cache_one = {60, 5, 15, 60, 20, 0}; + static Setting _set_cache_two = {60, 5, 15, 60, 20, 0}; //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 - Setting* setting = &_set_cache_one; - Setting* setting_copy = &_set_cache_two; + static Setting* setting = &_set_cache_one; + static Setting* setting_copy = &_set_cache_two; + + //将配置信息返回成一个字符串输出 + // static auto settting_info = [](Setting* set = telemeter::setting) -> std::string + // { + // return fmt::format("mir load record interval: -{0}\n \ + // nmir database log interval: -{1}\n \ + // mir max disbeat time: -{2}\n \ + // cli login cache time: -{3}\n \ + // load balance interval: -{4}\n \ + // clear mirs data time: -{5}", + // set->mir_load_record_interval_, + // set->mir_dblog_interval_, + // set->mir_max_disbeat_time_, + // set->cli_login_cache_time_, + // set->load_balance_interval_, + // set->clear_mirs_data_time_); + // }; #endif #ifdef SRC_MIRROR_H - Setting _set_cache_one = {600,1,60,600,55}; - Setting _set_cache_two = {600,1,60,600,55}; - - Setting* setting = &_set_cache_one; - Setting* setting_copy = &_set_cache_two; #endif - - - - - //获取本机负载情况的函数, 需要统计空闲内存占比, cpu负载, 空闲磁盘占比 - LoadLevel getLocalLoadLevel(); - - //int getLocalMemLoad(); - //int getLocalSevLoad(); - //int getLocalNetLoad(); + //获取本机负载情况的函数, 需要统计空闲内存占比, cpu负载, 空闲磁盘占比 + //LoadLevel getLocalLoadLevel(); + + //int getLocalMemLoad(); + //int getLocalSevLoad(); + //int getLocalNetLoad(); } diff --git a/include/Third_Lib/boost/any.hpp b/include/Third_Lib/boost/any.hpp new file mode 100644 index 0000000..892d47c --- /dev/null +++ b/include/Third_Lib/boost/any.hpp @@ -0,0 +1,342 @@ +// See http://www.boost.org/libs/any for Documentation. + +#ifndef BOOST_ANY_INCLUDED +#define BOOST_ANY_INCLUDED + +#if defined(_MSC_VER) +# pragma once +#endif + +// what: variant type boost::any +// who: contributed by Kevlin Henney, +// with features contributed and bugs found by +// Antony Polukhin, Ed Brey, Mark Rodgers, +// Peter Dimov, and James Curran +// when: July 2001, April 2013 - 2020 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + class any + { + public: // structors + + BOOST_CONSTEXPR any() BOOST_NOEXCEPT + : content(0) + { + } + + template + any(const ValueType & value) + : content(new holder< + BOOST_DEDUCED_TYPENAME remove_cv::type>::type + >(value)) + { + } + + any(const any & other) + : content(other.content ? other.content->clone() : 0) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Move constructor + any(any&& other) BOOST_NOEXCEPT + : content(other.content) + { + other.content = 0; + } + + // Perfect forwarding of ValueType + template + any(ValueType&& value + , typename boost::disable_if >::type* = 0 // disable if value has type `any&` + , typename boost::disable_if >::type* = 0) // disable if value has type `const ValueType&&` + : content(new holder< typename decay::type >(static_cast(value))) + { + } +#endif + + ~any() BOOST_NOEXCEPT + { + delete content; + } + + public: // modifiers + + any & swap(any & rhs) BOOST_NOEXCEPT + { + placeholder* tmp = content; + content = rhs.content; + rhs.content = tmp; + return *this; + } + + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template + any & operator=(const ValueType & rhs) + { + any(rhs).swap(*this); + return *this; + } + + any & operator=(any rhs) + { + rhs.swap(*this); + return *this; + } + +#else + any & operator=(const any& rhs) + { + any(rhs).swap(*this); + return *this; + } + + // move assignment + any & operator=(any&& rhs) BOOST_NOEXCEPT + { + rhs.swap(*this); + any().swap(rhs); + return *this; + } + + // Perfect forwarding of ValueType + template + any & operator=(ValueType&& rhs) + { + any(static_cast(rhs)).swap(*this); + return *this; + } +#endif + + public: // queries + + bool empty() const BOOST_NOEXCEPT + { + return !content; + } + + void clear() BOOST_NOEXCEPT + { + any().swap(*this); + } + + const boost::typeindex::type_info& type() const BOOST_NOEXCEPT + { + return content ? content->type() : boost::typeindex::type_id().type_info(); + } + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + private: // types +#else + public: // types (public so any_cast can be non-friend) +#endif + + class BOOST_SYMBOL_VISIBLE placeholder + { + public: // structors + + virtual ~placeholder() + { + } + + public: // queries + + virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0; + + virtual placeholder * clone() const = 0; + + }; + + template + class holder +#ifndef BOOST_NO_CXX11_FINAL + final +#endif + : public placeholder + { + public: // structors + + holder(const ValueType & value) + : held(value) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + holder(ValueType&& value) + : held(static_cast< ValueType&& >(value)) + { + } +#endif + public: // queries + + const boost::typeindex::type_info& type() const BOOST_NOEXCEPT BOOST_OVERRIDE + { + return boost::typeindex::type_id().type_info(); + } + + placeholder * clone() const BOOST_OVERRIDE + { + return new holder(held); + } + + public: // representation + + ValueType held; + + private: // intentionally left unimplemented + holder & operator=(const holder &); + }; + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + + private: // representation + + template + friend ValueType * any_cast(any *) BOOST_NOEXCEPT; + + template + friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT; + +#else + + public: // representation (public so any_cast can be non-friend) + +#endif + + placeholder * content; + + }; + + inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT +{ + lhs.swap(rhs); +} + +class BOOST_SYMBOL_VISIBLE bad_any_cast : +#ifndef BOOST_NO_RTTI +public std::bad_cast +#else +public std::exception +#endif +{ +public: +const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE + { + return "boost::bad_any_cast: " + "failed conversion using boost::any_cast"; + } +}; + +template +ValueType * any_cast(any * operand) BOOST_NOEXCEPT +{ +return operand && operand->type() == boost::typeindex::type_id() +? boost::addressof( +static_cast::type> *>(operand->content)->held +) +: 0; +} + +template +inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT +{ +return any_cast(const_cast(operand)); +} + +template +ValueType any_cast(any & operand) +{ + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + + + nonref * result = any_cast(boost::addressof(operand)); + if(!result) + boost::throw_exception(bad_any_cast()); + + // Attempt to avoid construction of a temporary object in cases when + // `ValueType` is not a reference. Example: + // `static_cast(*result);` + // which is equal to `std::string(*result);` + typedef BOOST_DEDUCED_TYPENAME boost::conditional< + boost::is_reference::value, + ValueType, + BOOST_DEDUCED_TYPENAME boost::add_reference::type + >::type ref_type; + +#ifdef BOOST_MSVC + # pragma warning(push) +# pragma warning(disable: 4172) // "returning address of local variable or temporary" but *result is not local! +#endif + return static_cast(*result); +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +} + +template +inline ValueType any_cast(const any & operand) +{ + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + return any_cast(const_cast(operand)); +} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template +inline ValueType any_cast(any&& operand) +{ + BOOST_STATIC_ASSERT_MSG( + boost::is_rvalue_reference::value /*true if ValueType is rvalue or just a value*/ + || boost::is_const< typename boost::remove_reference::type >::value, + "boost::any_cast shall not be used for getting nonconst references to temporary objects" + ); + return any_cast(operand); +} +#endif + + +// Note: The "unsafe" versions of any_cast are not part of the +// public interface and may be removed at any time. They are +// required where we know what type is stored in the any and can't +// use typeid() comparison, e.g., when our types may travel across +// different shared libraries. +template +inline ValueType * unsafe_any_cast(any * operand) BOOST_NOEXCEPT +{ +return boost::addressof( +static_cast *>(operand->content)->held +); +} + +template +inline const ValueType * unsafe_any_cast(const any * operand) BOOST_NOEXCEPT +{ +return unsafe_any_cast(const_cast(operand)); +} +} + +// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. +// Copyright Antony Polukhin, 2013-2020. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#endif diff --git a/include/Third_Lib/cppcodec/base32_crockford.hpp b/include/Third_Lib/cppcodec/base32_crockford.hpp new file mode 100644 index 0000000..6c2ae36 --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_crockford.hpp @@ -0,0 +1,91 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE32_CROCKFORD +#define CPPCODEC_BASE32_CROCKFORD + +#include "detail/codec.hpp" +#include "detail/base32.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char base32_crockford_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // at index 10 + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 18 - no I + 'J', 'K', // 20 - no L + 'M', 'N', // 22 - no O + 'P', 'Q', 'R', 'S', 'T', // 27 - no U + 'V', 'W', 'X', 'Y', 'Z' // 32 +}; + +class base32_crockford_base +{ +public: + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base32_crockford_alphabet) == 32, "base32 alphabet must have 32 values"); + return sizeof(base32_crockford_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base32_crockford_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Hex decoding is always case-insensitive (even in RFC 4648), the question + // is only for encoding whether to use upper-case or lower-case letters. + return (c == 'O' || c == 'o') ? '0' + : (c == 'I' || c == 'i' || c == 'L' || c == 'l') ? '1' + : (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') + : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char) { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char c) { + return c == '-'; // "Hyphens (-) can be inserted into strings [for readability]." + } +}; + +// base32_crockford is a concatenative iterative (i.e. streaming) interpretation of Crockford base32. +// It interprets the statement "zero-extend the number to make its bit-length a multiple of 5" +// to mean zero-extending it on the right. +// (The other possible interpretation is base32_crockford_num, a place-based single number encoding system. +// See http://merrigrove.blogspot.ca/2014/04/what-heck-is-base64-encoding-really.html for more info.) +class base32_crockford : public base32_crockford_base +{ +public: + template using codec_impl = stream_codec; +}; + +} // namespace detail + +using base32_crockford = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE32_CROCKFORD diff --git a/include/Third_Lib/cppcodec/base32_default_crockford.hpp b/include/Third_Lib/cppcodec/base32_default_crockford.hpp new file mode 100644 index 0000000..73e94eb --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_default_crockford.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE32_DEFAULT_CROCKFORD +#define CPPCODEC_BASE32_DEFAULT_CROCKFORD + +#include "base32_crockford.hpp" + +using base32 = cppcodec::base32_crockford; + +#endif // CPPCODEC_BASE32_DEFAULT_CROCKFORD diff --git a/include/Third_Lib/cppcodec/base32_default_hex.hpp b/include/Third_Lib/cppcodec/base32_default_hex.hpp new file mode 100644 index 0000000..4cd8336 --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_default_hex.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015, 2016 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE32_DEFAULT_HEX +#define CPPCODEC_BASE32_DEFAULT_HEX + +#include "base32_hex.hpp" + +using base32 = cppcodec::base32_hex; + +#endif // CPPCODEC_BASE32_DEFAULT_HEX diff --git a/include/Third_Lib/cppcodec/base32_default_rfc4648.hpp b/include/Third_Lib/cppcodec/base32_default_rfc4648.hpp new file mode 100644 index 0000000..75561bc --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_default_rfc4648.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE32_DEFAULT_RFC4648 +#define CPPCODEC_BASE32_DEFAULT_RFC4648 + +#include "base32_rfc4648.hpp" + +using base32 = cppcodec::base32_rfc4648; + +#endif // CPPCODEC_BASE32_DEFAULT_RFC4648 diff --git a/include/Third_Lib/cppcodec/base32_hex.hpp b/include/Third_Lib/cppcodec/base32_hex.hpp new file mode 100644 index 0000000..ce1d84d --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_hex.hpp @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2015, 2016 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE32_HEX +#define CPPCODEC_BASE32_HEX + +#include "detail/codec.hpp" +#include "detail/base32.hpp" + +namespace cppcodec { + +namespace detail { + +// RFC 4648 also specifies a hex encoding system which uses 0-9, then A-V. +static constexpr const char base32_hex_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V' +}; + +class base32_hex +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base32_hex_alphabet) == 32, "base32 alphabet must have 32 values"); + return sizeof(base32_hex_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base32_hex_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Lower-case letters are accepted, though not generally expected. + return (c >= 'a' && c <= 'v') ? (c - 'a' + 'A') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base32 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base32_hex = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE32_HEX diff --git a/include/Third_Lib/cppcodec/base32_rfc4648.hpp b/include/Third_Lib/cppcodec/base32_rfc4648.hpp new file mode 100644 index 0000000..c039702 --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_rfc4648.hpp @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE32_RFC4648 +#define CPPCODEC_BASE32_RFC4648 + +#include "detail/codec.hpp" +#include "detail/base32.hpp" + +namespace cppcodec { + +namespace detail { + +// RFC 4648 uses a simple alphabet: A-Z starting at index 0, then 2-7 starting at index 26. +static constexpr const char base32_rfc4648_alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', // at index 26 + '2', '3', '4', '5', '6', '7' +}; + +class base32_rfc4648 +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base32_rfc4648_alphabet) == 32, "base32 alphabet must have 32 values"); + return sizeof(base32_rfc4648_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base32_rfc4648_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Lower-case letters are accepted, though not generally expected. + return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base32 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base32_rfc4648 = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE32_RFC4648 diff --git a/include/Third_Lib/cppcodec/base64_default_rfc4648.hpp b/include/Third_Lib/cppcodec/base64_default_rfc4648.hpp new file mode 100644 index 0000000..3b39a00 --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_default_rfc4648.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE64_DEFAULT_RFC4648 +#define CPPCODEC_BASE64_DEFAULT_RFC4648 + +#include "base64_rfc4648.hpp" + +using base64 = cppcodec::base64_rfc4648; + +#endif // CPPCODEC_BASE64_DEFAULT_RFC4648 diff --git a/include/Third_Lib/cppcodec/base64_default_url.hpp b/include/Third_Lib/cppcodec/base64_default_url.hpp new file mode 100644 index 0000000..7db2a39 --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_default_url.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE64_DEFAULT_URL +#define CPPCODEC_BASE64_DEFAULT_URL + +#include "base64_url.hpp" + +using base64 = cppcodec::base64_url; + +#endif // CPPCODEC_BASE64_DEFAULT_URL diff --git a/include/Third_Lib/cppcodec/base64_default_url_unpadded.hpp b/include/Third_Lib/cppcodec/base64_default_url_unpadded.hpp new file mode 100644 index 0000000..3173966 --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_default_url_unpadded.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2016 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE64_DEFAULT_URL_UNPADDED +#define CPPCODEC_BASE64_DEFAULT_URL_UNPADDED + +#include "base64_url_unpadded.hpp" + +using base64 = cppcodec::base64_url_unpadded; + +#endif // CPPCODEC_BASE64_DEFAULT_URL_UNPADDED diff --git a/include/Third_Lib/cppcodec/base64_rfc4648.hpp b/include/Third_Lib/cppcodec/base64_rfc4648.hpp new file mode 100644 index 0000000..717dcec --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_rfc4648.hpp @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE64_RFC4648 +#define CPPCODEC_BASE64_RFC4648 + +#include "detail/codec.hpp" +#include "detail/base64.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char base64_rfc4648_alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +class base64_rfc4648 +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base64_rfc4648_alphabet) == 64, "base64 alphabet must have 64 values"); + return sizeof(base64_rfc4648_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base64_rfc4648_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) { return c; } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base64 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base64_rfc4648 = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE64_RFC4648 diff --git a/include/Third_Lib/cppcodec/base64_url.hpp b/include/Third_Lib/cppcodec/base64_url.hpp new file mode 100644 index 0000000..04c2f8b --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_url.hpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE64_URL +#define CPPCODEC_BASE64_URL + +#include "detail/codec.hpp" +#include "detail/base64.hpp" + +namespace cppcodec { + +namespace detail { + +// The URL and filename safe alphabet is also specified by RFC4648, named "base64url". +// We keep the underscore ("base64_url") for consistency with the other codec variants. +static constexpr const char base64_url_alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' +}; + +class base64_url +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base64_url_alphabet) == 64, "base64 alphabet must have 64 values"); + return sizeof(base64_url_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base64_url_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) { return c; } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base64 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base64_url = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE64_URL diff --git a/include/Third_Lib/cppcodec/base64_url_unpadded.hpp b/include/Third_Lib/cppcodec/base64_url_unpadded.hpp new file mode 100644 index 0000000..e9a5d3f --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_url_unpadded.hpp @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2016 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_BASE64_URL_UNPADDED +#define CPPCODEC_BASE64_URL_UNPADDED + +#include "base64_url.hpp" + +namespace cppcodec { + +namespace detail { + +class base64_url_unpadded : public base64_url +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } +}; + +} // namespace detail + +using base64_url_unpadded = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE64_URL_UNPADDED diff --git a/include/Third_Lib/cppcodec/data/access.hpp b/include/Third_Lib/cppcodec/data/access.hpp new file mode 100644 index 0000000..432a3c7 --- /dev/null +++ b/include/Third_Lib/cppcodec/data/access.hpp @@ -0,0 +1,328 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_DETAIL_DATA_ACCESS +#define CPPCODEC_DETAIL_DATA_ACCESS + +#include // for size_t +#include // for static_assert() checking that string will be optimized +#include // for std::enable_if, std::remove_reference, and such +#include // for std::declval +#include // for static_assert() checking that vector will be optimized + +#include "../detail/config.hpp" // for CPPCODEC_ALWAYS_INLINE + +namespace cppcodec { +namespace data { + +// This file contains a number of templated data accessors that can be +// implemented in the cppcodec::data namespace for types that don't fulfill +// the default type requirements: +// For result types: init(Result&, ResultState&, size_t capacity), +// put(Result&, ResultState&, char), finish(Result&, State&) +// For const (read-only) types: char_data(const T&) +// For both const and result types: size(const T&) + +template +CPPCODEC_ALWAYS_INLINE size_t size(const T& t) { return t.size(); } + +template +CPPCODEC_ALWAYS_INLINE constexpr size_t size(const T (&t)[N]) noexcept { + return (void)t, N * sizeof(t[0]); +} + +class general_t {}; +class specific_t : public general_t {}; + +class empty_result_state { + template + CPPCODEC_ALWAYS_INLINE void size(const Result& result) { return size(result); } +}; + +// SFINAE: Generic fallback in case no specific state function applies. +template +CPPCODEC_ALWAYS_INLINE empty_result_state create_state(Result&, general_t) +{ + return empty_result_state(); +} + +// +// Generic templates for containers: Use these init()/put()/finish() +// implementations if no specialization was found. +// + +template +CPPCODEC_ALWAYS_INLINE void init(Result& result, empty_result_state&, size_t capacity) +{ + result.resize(0); + result.reserve(capacity); +} + +template +CPPCODEC_ALWAYS_INLINE void finish(Result&, empty_result_state&) +{ + // Default is to push_back(), which already increases the size. +} + +// For the put() default implementation, we try calling push_back() with either uint8_t or char, +// whichever compiles. Scary-fancy template magic from http://stackoverflow.com/a/1386390. +namespace fallback { + struct flag { char c[2]; }; // sizeof > 1 + flag put_uint8(...); + + int operator,(flag, flag); + template void operator,(flag, T&); // map everything else to void + char operator,(int, flag); // sizeof 1 +} + +template inline void put_uint8(Result& result, uint8_t c) { result.push_back(c); } + +template struct put_impl; +template <> struct put_impl { // put_uint8() available + template + static CPPCODEC_ALWAYS_INLINE void put(Result& result, uint8_t c) + { + put_uint8(result, c); + } +}; +template <> struct put_impl { // put_uint8() not available + template + static CPPCODEC_ALWAYS_INLINE void put(Result& result, uint8_t c) + { + result.push_back(static_cast(c)); + } +}; + +template +CPPCODEC_ALWAYS_INLINE void put(Result& result, empty_result_state&, uint8_t c) +{ + using namespace fallback; + put_impl::put(result, c); +} + +// +// Specialization for container types with direct mutable data access, +// e.g. std::vector. +// +// The expected way to specialize is to draft a new xyz_result_state type and +// return an instance of it from a create_state() template specialization. +// You can then create overloads for init(), put() and finish() +// for the new result state type. +// +// If desired, a non-templated overload for both specific types +// (result & state) can be added to tailor it to that particular result type. +// + +template +constexpr auto data_is_mutable(T* t) -> decltype(t->data()[size_t(0)] = 'x', bool()) +{ + return (void)t, true; +} +constexpr bool data_is_mutable(...) { return false; } + +template +class direct_data_access_result_state +{ +public: + CPPCODEC_ALWAYS_INLINE void init(Result& result, size_t capacity) + { + // reserve() may not actually allocate the storage right away, + // and it isn't guaranteed that it will be untouched upon the + //.next resize(). In that light, resize from the start and + // slightly reduce the size at the end if necessary. + result.resize(capacity); + + // result.data() may perform a calculation to retrieve the address. + // E.g. std::string (since C++11) will use small string optimization, + // so it needs to check if it's using allocated data or (ab)using + // its own member variables interpreted as char array. + // (This result_state is used for std::string starting with C++17.) + // Conditional code paths are slow so we only do it once, at the start. + m_buffer = result.data(); + } + CPPCODEC_ALWAYS_INLINE void put(Result&, char c) + { + m_buffer[m_offset++] = c; + } + CPPCODEC_ALWAYS_INLINE void finish(Result& result) + { + result.resize(m_offset); + } + CPPCODEC_ALWAYS_INLINE size_t size(const Result&) + { + return m_offset; + } +private: + // Make sure to get the mutable buffer decltype by using assignment. + typename std::remove_reference< + decltype(std::declval().data()[size_t(0)] = 'x')>::type* m_buffer; + size_t m_offset = 0; +}; + +// SFINAE: Select a specific state based on the result type and possible result state type. +// Implement this if direct data access (`result.data()[0] = 'x') isn't already possible +// and you want to specialize it for your own result type. +// Note: The enable_if should ideally be part of the class declaration, +// but Visual Studio C++ will not compile it that way. +// Have it here in the factory function instead. +template (nullptr))>::type> +CPPCODEC_ALWAYS_INLINE direct_data_access_result_state create_state(Result&, specific_t) +{ + return direct_data_access_result_state(); +} + +static_assert(std::is_same< + decltype(create_state(*static_cast*>(nullptr), specific_t())), + direct_data_access_result_state>>::value, + "std::vector must be handled by direct_data_access_result_state"); + +// Specialized init(), put() and finish() functions for direct_data_access_result_state. +template +CPPCODEC_ALWAYS_INLINE void init(Result& result, direct_data_access_result_state& state, size_t capacity) +{ + state.init(result, capacity); +} + +template +CPPCODEC_ALWAYS_INLINE void put(Result& result, direct_data_access_result_state& state, char c) +{ + state.put(result, c); +} + +template +CPPCODEC_ALWAYS_INLINE void finish(Result& result, direct_data_access_result_state& state) +{ + state.finish(result); +} + +// +// Specialization for container types with direct mutable array access, +// e.g. std::string. This is generally faster because bound checks are +// minimal and operator[] is more likely noexcept. In addition, +// std::string::push_back() needs to write a null character on every +// expansion, which should be more efficient when done in bulk by resize(). +// +// Compared to the above, tracking an extra offset variable is cheap. +// + +template +constexpr auto array_access_is_mutable(T* t) -> decltype((*t)[size_t(0)] = 'x', bool()) +{ + return (void)t, true; +} +constexpr bool array_access_is_mutable(...) { return false; } + +template +class array_access_result_state +{ +public: + CPPCODEC_ALWAYS_INLINE void init(Result& result, size_t capacity) + { + // reserve() may not actually allocate the storage right away, + // and it isn't guaranteed that it will be untouched upon the + //.next resize(). In that light, resize from the start and + // slightly reduce the size at the end if necessary. + result.resize(capacity); + } + CPPCODEC_ALWAYS_INLINE void put(Result& result, char c) + { + result[m_offset++] = c; + } + CPPCODEC_ALWAYS_INLINE void finish(Result& result) + { + result.resize(m_offset); + } + CPPCODEC_ALWAYS_INLINE size_t size(const Result&) + { + return m_offset; + } +private: + size_t m_offset = 0; +}; + +// SFINAE: Select a specific state based on the result type and possible result state type. +// Note: The enable_if should ideally be part of the class declaration, +// but Visual Studio C++ will not compile it that way. +// Have it here in the factory function instead. +template (nullptr)) // no more than one template option + && array_access_is_mutable(static_cast(nullptr))>::type> +CPPCODEC_ALWAYS_INLINE array_access_result_state create_state(Result&, specific_t) +{ + return array_access_result_state(); +} + +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) +static_assert(std::is_same< + decltype(create_state(*static_cast(nullptr), specific_t())), + direct_data_access_result_state>::value, + "std::string (C++17 and later) must be handled by direct_data_access_result_state"); +#elif __cplusplus < 201703 && !defined(_MSVC_LANG) // we can't trust MSVC to set this right +static_assert(std::is_same< + decltype(create_state(*static_cast(nullptr), specific_t())), + array_access_result_state>::value, + "std::string (pre-C++17) must be handled by array_access_result_state"); +#endif + +// Specialized init(), put() and finish() functions for array_access_result_state. +template +CPPCODEC_ALWAYS_INLINE void init(Result& result, array_access_result_state& state, size_t capacity) +{ + state.init(result, capacity); +} + +template +CPPCODEC_ALWAYS_INLINE void put(Result& result, array_access_result_state& state, char c) +{ + state.put(result, c); +} + +template +CPPCODEC_ALWAYS_INLINE void finish(Result& result, array_access_result_state& state) +{ + state.finish(result); +} + +// char_data() is only used to read, not for result buffers. +template inline const char* char_data(const T& t) +{ + return reinterpret_cast(t.data()); +} +template inline const char* char_data(const T (&t)[N]) noexcept +{ + return reinterpret_cast(&(t[0])); +} + +template inline const uint8_t* uchar_data(const T& t) +{ + return reinterpret_cast(char_data(t)); +} + +} // namespace data +} // namespace cppcodec + +#endif diff --git a/include/Third_Lib/cppcodec/data/raw_result_buffer.hpp b/include/Third_Lib/cppcodec/data/raw_result_buffer.hpp new file mode 100644 index 0000000..65b0de5 --- /dev/null +++ b/include/Third_Lib/cppcodec/data/raw_result_buffer.hpp @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_DETAIL_RAW_RESULT_BUFFER +#define CPPCODEC_DETAIL_RAW_RESULT_BUFFER + +#include // for size_t +#include // for abort() + +#include "access.hpp" + +namespace cppcodec { +namespace data { + +class raw_result_buffer +{ +public: + raw_result_buffer(char* data, size_t capacity) + : m_ptr(data + capacity) + , m_begin(data) + { + } + + CPPCODEC_ALWAYS_INLINE void push_back(char c) { *m_ptr = c; ++m_ptr; } + CPPCODEC_ALWAYS_INLINE size_t size() const { return m_ptr - m_begin; } + CPPCODEC_ALWAYS_INLINE void resize(size_t size) { m_ptr = m_begin + size; } + +private: + char* m_ptr; + char* m_begin; +}; + + +template <> inline void init( + raw_result_buffer& result, empty_result_state&, size_t capacity) +{ + // This version of init() doesn't do a reserve(), and instead checks whether the + // initial size (capacity) is enough before resetting m_ptr to m_begin. + // The codec is expected not to exceed this capacity. + if (capacity > result.size()) { + abort(); + } + result.resize(0); +} +template <> inline void finish(raw_result_buffer&, empty_result_state&) { } + +} // namespace data +} // namespace cppcodec + +#endif diff --git a/include/Third_Lib/cppcodec/detail/base32.hpp b/include/Third_Lib/cppcodec/detail/base32.hpp new file mode 100644 index 0000000..7113b7a --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/base32.hpp @@ -0,0 +1,166 @@ +/** + * Copyright (C) 2015 Trustifier Inc. + * Copyright (C) 2015 Ahmed Masud + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * 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. + * + * Adapted from https://github.com/ahmed-masud/libbase32, + * commit 79761b2b79b0545697945efe0987a8d3004512f9. + * Quite different now. + */ + +#ifndef CPPCODEC_DETAIL_BASE32 +#define CPPCODEC_DETAIL_BASE32 + +#include +#include // for abort() + +#include "../data/access.hpp" +#include "../parse_error.hpp" +#include "config.hpp" +#include "stream_codec.hpp" + +namespace cppcodec { +namespace detail { + +template +class base32 : public CodecVariant::template codec_impl> +{ +public: + static inline constexpr uint8_t binary_block_size() { return 5; } + static inline constexpr uint8_t encoded_block_size() { return 8; } + + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t num_encoded_tail_symbols(uint8_t num_bytes) + { + return (num_bytes == 1) ? 2 // 2 symbols, 6 padding characters + : (num_bytes == 2) ? 4 // 4 symbols, 4 padding characters + : (num_bytes == 3) ? 5 // 5 symbols, 3 padding characters + : (num_bytes == 4) ? 7 // 7 symbols, 1 padding characters + : throw std::domain_error("invalid number of bytes in a tail block"); + } + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t index( + const uint8_t* b /*binary block*/) noexcept + { + static_assert(I >= 0 && I < encoded_block_size(), + "invalid encoding symbol index in a block"); + + return (I == 0) ? ((b[0] >> 3) & 0x1F) // first 5 bits + : (I == 1) ? (((b[0] << 2) & 0x1C) | ((b[1] >> 6) & 0x3)) + : (I == 2) ? ((b[1] >> 1) & 0x1F) + : (I == 3) ? (((b[1] << 4) & 0x10) | ((b[2] >> 4) & 0xF)) + : (I == 4) ? (((b[2] << 1) & 0x1E) | ((b[3] >> 7) & 0x1)) + : (I == 5) ? ((b[3] >> 2) & 0x1F) + : (I == 6) ? (((b[3] << 3) & 0x18) | ((b[4] >> 5) & 0x7)) + : /*I == 7*/ (b[4] & 0x1F); // last 5 bits; + } + + template + using uint8_if = typename std::enable_if::type; + + template + static CPPCODEC_ALWAYS_INLINE constexpr + uint8_if index_last( + const uint8_t* b /*binary block*/) noexcept + { + return (I == 1) ? ((b[0] << 2) & 0x1C) // abbreviated 2nd symbol + : (I == 3) ? ((b[1] << 4) & 0x10) // abbreviated 4th symbol + : (I == 4) ? ((b[2] << 1) & 0x1E) // abbreviated 5th symbol + : /*I == 6*/ ((b[3] << 3) & 0x18); // abbreviated 7th symbol + } + + template + static CPPCODEC_ALWAYS_INLINE + uint8_if index_last( + const uint8_t* /*binary block*/) + { + throw std::domain_error("invalid last encoding symbol index in a tail"); + } + + template + static CPPCODEC_ALWAYS_INLINE void decode_block( + Result& decoded, ResultState&, const alphabet_index_t* idx); + + template + static CPPCODEC_ALWAYS_INLINE void decode_tail( + Result& decoded, ResultState&, const alphabet_index_t* idx, size_t idx_len); +}; + +// +// 11111111 10101010 10110011 10111100 10010100 +// => 11111 11110 10101 01011 00111 01111 00100 10100 +// + +template +template +CPPCODEC_ALWAYS_INLINE void base32::decode_block( + Result& decoded, ResultState& state, const alphabet_index_t* idx) +{ + put(decoded, state, static_cast(((idx[0] << 3) & 0xF8) | ((idx[1] >> 2) & 0x7))); + put(decoded, state, static_cast(((idx[1] << 6) & 0xC0) | ((idx[2] << 1) & 0x3E) | ((idx[3] >> 4) & 0x1))); + put(decoded, state, static_cast(((idx[3] << 4) & 0xF0) | ((idx[4] >> 1) & 0xF))); + put(decoded, state, static_cast(((idx[4] << 7) & 0x80) | ((idx[5] << 2) & 0x7C) | ((idx[6] >> 3) & 0x3))); + put(decoded, state, static_cast(((idx[6] << 5) & 0xE0) | (idx[7] & 0x1F))); +} + +template +template +CPPCODEC_ALWAYS_INLINE void base32::decode_tail( + Result& decoded, ResultState& state, const alphabet_index_t* idx, size_t idx_len) +{ + if (idx_len == 1) { + throw invalid_input_length( + "invalid number of symbols in last base32 block: found 1, expected 2, 4, 5 or 7"); + } + if (idx_len == 3) { + throw invalid_input_length( + "invalid number of symbols in last base32 block: found 3, expected 2, 4, 5 or 7"); + } + if (idx_len == 6) { + throw invalid_input_length( + "invalid number of symbols in last base32 block: found 6, expected 2, 4, 5 or 7"); + } + + // idx_len == 2: decoded size 1 + put(decoded, state, static_cast(((idx[0] << 3) & 0xF8) | ((idx[1] >> 2) & 0x7))); + if (idx_len == 2) { + return; + } + // idx_len == 4: decoded size 2 + put(decoded, state, static_cast(((idx[1] << 6) & 0xC0) | ((idx[2] << 1) & 0x3E) | ((idx[3] >> 4) & 0x1))); + if (idx_len == 4) { + return; + } + // idx_len == 5: decoded size 3 + put(decoded, state, static_cast(((idx[3] << 4) & 0xF0) | ((idx[4] >> 1) & 0xF))); + if (idx_len == 5) { + return; + } + // idx_len == 7: decoded size 4 + put(decoded, state, static_cast(((idx[4] << 7) & 0x80) | ((idx[5] << 2) & 0x7C) | ((idx[6] >> 3) & 0x3))); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_BASE32 diff --git a/include/Third_Lib/cppcodec/detail/base64.hpp b/include/Third_Lib/cppcodec/detail/base64.hpp new file mode 100644 index 0000000..b6db6d7 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/base64.hpp @@ -0,0 +1,132 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2013 Adam Rudd (bit calculations) + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * 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. + * + * Bit calculations adapted from https://github.com/adamvr/arduino-base64, + * commit 999595783185a0afcba156d7276dfeaa9cb5382f. + */ + +#ifndef CPPCODEC_DETAIL_BASE64 +#define CPPCODEC_DETAIL_BASE64 + +#include +#include + +#include "../data/access.hpp" +#include "../parse_error.hpp" +#include "config.hpp" +#include "stream_codec.hpp" + +namespace cppcodec { +namespace detail { + +template +class base64 : public CodecVariant::template codec_impl> +{ +public: + static inline constexpr uint8_t binary_block_size() { return 3; } + static inline constexpr uint8_t encoded_block_size() { return 4; } + + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t num_encoded_tail_symbols(uint8_t num_bytes) + { + return (num_bytes == 1) ? 2 // 2 symbols, 2 padding characters + : (num_bytes == 2) ? 3 // 3 symbols, 1 padding character + : throw std::domain_error("invalid number of bytes in a tail block"); + } + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t index( + const uint8_t* b /*binary block*/) noexcept + { + static_assert(I >= 0 && I < encoded_block_size(), + "invalid encoding symbol index in a block"); + + return (I == 0) ? (b[0] >> 2) // first 6 bits + : (I == 1) ? (((b[0] & 0x3) << 4) | (b[1] >> 4)) + : (I == 2) ? (((b[1] & 0xF) << 2) | (b[2] >> 6)) + : /*I == 3*/ (b[2] & 0x3F); // last 6 bits + } + + template + using uint8_if = typename std::enable_if::type; + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_if index_last( + const uint8_t* b /*binary block*/) noexcept + { + return (I == 1) ? ((b[0] & 0x3) << 4) // abbreviated 2nd symbol + : /*I == 2*/ ((b[1] & 0xF) << 2); // abbreviated 3rd symbol + } + + template + static CPPCODEC_ALWAYS_INLINE uint8_if index_last( + const uint8_t* /*binary block*/) + { + throw std::domain_error("invalid last encoding symbol index in a tail"); + } + + template + static CPPCODEC_ALWAYS_INLINE void decode_block( + Result& decoded, ResultState&, const alphabet_index_t* idx); + + template + static CPPCODEC_ALWAYS_INLINE void decode_tail( + Result& decoded, ResultState&, const alphabet_index_t* idx, size_t idx_len); +}; + + +template +template +CPPCODEC_ALWAYS_INLINE void base64::decode_block( + Result& decoded, ResultState& state, const alphabet_index_t* idx) +{ + uint_fast32_t dec = (idx[0] << 18) | (idx[1] << 12) | (idx[2] << 6) | idx[3]; + data::put(decoded, state, static_cast(dec >> 16)); + data::put(decoded, state, static_cast((dec >> 8) & 0xFF)); + data::put(decoded, state, static_cast(dec & 0xFF)); +} + +template +template +CPPCODEC_ALWAYS_INLINE void base64::decode_tail( + Result& decoded, ResultState& state, const alphabet_index_t* idx, size_t idx_len) +{ + if (idx_len == 1) { + throw invalid_input_length( + "invalid number of symbols in last base64 block: found 1, expected 2 or 3"); + } + + // idx_len == 2: decoded size 1 + data::put(decoded, state, static_cast((idx[0] << 2) + ((idx[1] & 0x30) >> 4))); + if (idx_len == 2) { + return; + } + + // idx_len == 3: decoded size 2 + data::put(decoded, state, static_cast(((idx[1] & 0xF) << 4) + ((idx[2] & 0x3C) >> 2))); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_BASE64 diff --git a/include/Third_Lib/cppcodec/detail/codec.hpp b/include/Third_Lib/cppcodec/detail/codec.hpp new file mode 100644 index 0000000..47d9802 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/codec.hpp @@ -0,0 +1,327 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_DETAIL_CODEC +#define CPPCODEC_DETAIL_CODEC + +#include +#include +#include +#include + +#include "../data/access.hpp" +#include "../data/raw_result_buffer.hpp" + +namespace cppcodec { +namespace detail { + +// SFINAE: Templates sometimes beat sensible overloads - make sure we don't call the wrong one. +template +struct non_numeric : std::enable_if::value> { }; + + +/** + * Public interface for all the codecs. For API documentation, see README.md. + */ +template +class codec +{ +public: + // + // Encoding + + // Convenient version, returns an std::string. + static std::string encode(const uint8_t* binary, size_t binary_size); + static std::string encode(const char* binary, size_t binary_size); + // static std::string encode(const T& binary); -> provided by template below + + // Convenient version with templated result type. + template static Result encode(const uint8_t* binary, size_t binary_size); + template static Result encode(const char* binary, size_t binary_size); + template > + static Result encode(const T& binary); + + // Reused result container version. Resizes encoded_result before writing to it. + template + static void encode(Result& encoded_result, const uint8_t* binary, size_t binary_size); + template + static void encode(Result& encoded_result, const char* binary, size_t binary_size); + template ::type* = nullptr> + static void encode(Result& encoded_result, const T& binary); + + // Raw pointer output, assumes pre-allocated memory with size > encoded_size(binary_size). + static size_t encode( + char* encoded_result, size_t encoded_buffer_size, + const uint8_t* binary, size_t binary_size) noexcept; + static size_t encode( + char* encoded_result, size_t encoded_buffer_size, + const char* binary, size_t binary_size) noexcept; + template + static size_t encode( + char* encoded_result, size_t encoded_buffer_size, + const T& binary) noexcept; + + // Calculate the exact length of the encoded string based on binary size. + static constexpr size_t encoded_size(size_t binary_size) noexcept; + + // + // Decoding + + // Convenient version, returns an std::vector. + static std::vector decode(const char* encoded, size_t encoded_size); + // static std::vector decode(const T& encoded); -> provided by template below + + // Convenient version with templated result type. + template static Result decode(const char* encoded, size_t encoded_size); + template , typename T = std::string> + static Result decode(const T& encoded); + + // Reused result container version. Resizes binary_result before writing to it. + template + static void decode(Result& binary_result, const char* encoded, size_t encoded_size); + template ::type* = nullptr> + static void decode(Result& binary_result, const T& encoded); + + // Raw pointer output, assumes pre-allocated memory with size > decoded_max_size(encoded_size). + static size_t decode( + uint8_t* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size); + static size_t decode( + char* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size); + template static size_t decode( + uint8_t* binary_result, size_t binary_buffer_size, const T& encoded); + template static size_t decode( + char* binary_result, size_t binary_buffer_size, const T& encoded); + + // Calculate the maximum size of the decoded binary buffer based on the encoded string length. + static constexpr size_t decoded_max_size(size_t encoded_size) noexcept; +}; + + +// +// Inline definitions of the above functions, using CRTP to call into CodecImpl +// + +// +// Encoding + +template +inline std::string codec::encode(const uint8_t* binary, size_t binary_size) +{ + return encode(binary, binary_size); +} + +template +inline std::string codec::encode(const char* binary, size_t binary_size) +{ + return encode(reinterpret_cast(binary), binary_size); +} + +template +template +inline Result codec::encode(const uint8_t* binary, size_t binary_size) +{ + Result encoded_result; + encode(encoded_result, binary, binary_size); + return encoded_result; +} + +template +template +inline Result codec::encode(const char* binary, size_t binary_size) +{ + return encode(reinterpret_cast(binary), binary_size); +} + +template +template +inline Result codec::encode(const T& binary) +{ + return encode(data::uchar_data(binary), data::size(binary)); +} + +template +template +inline void codec::encode( + Result& encoded_result, const uint8_t* binary, size_t binary_size) +{ + // This overload is where we reserve buffer capacity and call into CodecImpl. + size_t encoded_buffer_size = encoded_size(binary_size); + auto state = data::create_state(encoded_result, data::specific_t()); + data::init(encoded_result, state, encoded_buffer_size); + + CodecImpl::encode(encoded_result, state, binary, binary_size); + data::finish(encoded_result, state); + assert(data::size(encoded_result) == encoded_buffer_size); +} + +template +template +inline void codec::encode( + Result& encoded_result, const char* binary, size_t binary_size) +{ + encode(encoded_result, reinterpret_cast(binary), binary_size); +} + +template +template ::type*> +inline void codec::encode(Result& encoded_result, const T& binary) +{ + encode(encoded_result, data::uchar_data(binary), data::size(binary)); +} + +template +inline size_t codec::encode( + char* encoded_result, size_t encoded_buffer_size, + const uint8_t* binary, size_t binary_size) noexcept +{ + // This overload is where we wrap the result pointer & size. + data::raw_result_buffer encoded(encoded_result, encoded_buffer_size); + encode(encoded, binary, binary_size); + + size_t encoded_size = data::size(encoded); + if (encoded_size < encoded_buffer_size) { + encoded_result[encoded_size] = '\0'; + } + return encoded_size; +} + +template +inline size_t codec::encode( + char* encoded_result, size_t encoded_buffer_size, + const char* binary, size_t binary_size) noexcept +{ + // This overload is where we wrap the result pointer & size. + return encode(encoded_result, encoded_buffer_size, + reinterpret_cast(binary), binary_size); +} + +template +template +inline size_t codec::encode( + char* encoded_result, size_t encoded_buffer_size, + const T& binary) noexcept +{ + return encode(encoded_result, encoded_buffer_size, data::uchar_data(binary), data::size(binary)); +} + +template +inline constexpr size_t codec::encoded_size(size_t binary_size) noexcept +{ + return CodecImpl::encoded_size(binary_size); +} + + +// +// Decoding + +template +inline std::vector codec::decode(const char* encoded, size_t encoded_size) +{ + return decode>(encoded, encoded_size); +} + +template +template +inline Result codec::decode(const char* encoded, size_t encoded_size) +{ + Result result; + decode(result, encoded, encoded_size); + return result; +} + +template +template +inline Result codec::decode(const T& encoded) +{ + return decode(data::char_data(encoded), data::size(encoded)); +} + +template +template +inline void codec::decode(Result& binary_result, const char* encoded, size_t encoded_size) +{ + // This overload is where we reserve buffer capacity and call into CodecImpl. + size_t binary_buffer_size = decoded_max_size(encoded_size); + auto state = data::create_state(binary_result, data::specific_t()); + data::init(binary_result, state, binary_buffer_size); + + CodecImpl::decode(binary_result, state, encoded, encoded_size); + data::finish(binary_result, state); + assert(data::size(binary_result) <= binary_buffer_size); +} + + +template +template ::type*> +inline void codec::decode(Result& binary_result, const T& encoded) +{ + decode(binary_result, data::char_data(encoded), data::size(encoded)); +} + +template +inline size_t codec::decode( + uint8_t* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size) +{ + return decode(reinterpret_cast(binary_result), binary_buffer_size, encoded, encoded_size); +} + +template +inline size_t codec::decode( + char* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size) +{ + // This overload is where we wrap the result pointer & size. + data::raw_result_buffer binary(binary_result, binary_buffer_size); + decode(binary, encoded, encoded_size); + return data::size(binary); +} + +template +template +inline size_t codec::decode( + uint8_t* binary_result, size_t binary_buffer_size, const T& encoded) +{ + return decode(reinterpret_cast(binary_result), binary_buffer_size, encoded); +} + +template +template +inline size_t codec::decode(char* binary_result, size_t binary_buffer_size, const T& encoded) +{ + return decode(binary_result, binary_buffer_size, data::char_data(encoded), data::size(encoded)); +} + +template +inline constexpr size_t codec::decoded_max_size(size_t encoded_size) noexcept +{ + return CodecImpl::decoded_max_size(encoded_size); +} + + +} // namespace detail +} // namespace cppcodec + +#endif diff --git a/include/Third_Lib/cppcodec/detail/config.hpp b/include/Third_Lib/cppcodec/detail/config.hpp new file mode 100644 index 0000000..dc66f8f --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/config.hpp @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_DETAIL_CONFIG_HPP +#define CPPCODEC_DETAIL_CONFIG_HPP + +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +#if __GNUC__ || __has_attribute(always_inline) +#define CPPCODEC_ALWAYS_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define CPPCODEC_ALWAYS_INLINE inline __forceinline +#else +#define CPPCODEC_ALWAYS_INLINE inline +#endif + +#endif // CPPCODEC_DETAIL_CONFIG_HPP + diff --git a/include/Third_Lib/cppcodec/detail/hex.hpp b/include/Third_Lib/cppcodec/detail/hex.hpp new file mode 100644 index 0000000..f86be93 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/hex.hpp @@ -0,0 +1,114 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_DETAIL_HEX +#define CPPCODEC_DETAIL_HEX + +#include +#include // for abort() + +#include "../data/access.hpp" +#include "../parse_error.hpp" +#include "stream_codec.hpp" + +namespace cppcodec { +namespace detail { + +template +class hex : public CodecVariant::template codec_impl> +{ +public: + static inline constexpr uint8_t binary_block_size() { return 1; } + static inline constexpr uint8_t encoded_block_size() { return 2; } + + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t num_encoded_tail_symbols(uint8_t /*num_bytes*/) noexcept + { + // Hex encoding only works on full bytes so there are no tails, + // no padding characters, and this function should (must) never be called. + return 0; + } + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t index( + const uint8_t* b /*binary block*/) noexcept + { + static_assert(I >= 0 && I < encoded_block_size(), + "invalid encoding symbol index in a block"); + + return (I == 0) ? (b[0] >> 4) // first 4 bits + : /*I == 1*/ (b[0] & 0xF); // last 4 bits + } + + // With only 2 bytes, enc<1> will always result in a full index() call and + // enc<0> will be protected by a not-reached assertion, so we don't actually + // care about index_last() except optimizing it out as good as possible. + template + using uint8_if = typename std::enable_if::type; + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_if index_last( + const uint8_t* /*binary block*/) noexcept + { + return 0; + } + + template + static CPPCODEC_ALWAYS_INLINE uint8_if index_last( + const uint8_t* /*binary block*/) + { + throw std::domain_error("invalid last encoding symbol index in a tail"); + } + + template + static CPPCODEC_ALWAYS_INLINE void decode_block( + Result& decoded, ResultState&, const alphabet_index_t* idx); + + template + static CPPCODEC_ALWAYS_INLINE void decode_tail( + Result& decoded, ResultState&, const alphabet_index_t* idx, size_t idx_len); +}; + + +template +template +CPPCODEC_ALWAYS_INLINE void hex::decode_block( + Result& decoded, ResultState& state, const alphabet_index_t* idx) +{ + data::put(decoded, state, static_cast((idx[0] << 4) | idx[1])); +} + +template +template +CPPCODEC_ALWAYS_INLINE void hex::decode_tail( + Result&, ResultState&, const alphabet_index_t*, size_t) +{ + throw invalid_input_length( + "odd-length hex input is not supported by the streaming octet decoder, " + "use a place-based number decoder instead"); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_HEX diff --git a/include/Third_Lib/cppcodec/detail/stream_codec.hpp b/include/Third_Lib/cppcodec/detail/stream_codec.hpp new file mode 100644 index 0000000..ddc52e3 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/stream_codec.hpp @@ -0,0 +1,439 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_DETAIL_STREAM_CODEC +#define CPPCODEC_DETAIL_STREAM_CODEC + +#include +#include // for abort() +#include + +#include "../parse_error.hpp" +#include "config.hpp" + +namespace cppcodec { +namespace detail { + +using alphabet_index_t = uint_fast16_t; + +template +class stream_codec +{ +public: + template static void encode( + Result& encoded_result, ResultState&, const uint8_t* binary, size_t binary_size); + + template static void decode( + Result& binary_result, ResultState&, const char* encoded, size_t encoded_size); + + static constexpr size_t encoded_size(size_t binary_size) noexcept; + static constexpr size_t decoded_max_size(size_t encoded_size) noexcept; +}; + +template // default for CodecVariant::generates_padding() == false +struct padder { + template + static CPPCODEC_ALWAYS_INLINE void pad(Result&, ResultState&, SizeT) { } +}; + +template<> // specialization for CodecVariant::generates_padding() == true +struct padder { + template + static CPPCODEC_ALWAYS_INLINE void pad( + Result& encoded, ResultState& state, SizeT num_padding_characters) + { + for (SizeT i = 0; i < num_padding_characters; ++i) { + data::put(encoded, state, CodecVariant::padding_symbol()); + } + } +}; + +template +struct enc { + // Block encoding: Go from 0 to (block size - 1), append a symbol for each iteration unconditionally. + template + static CPPCODEC_ALWAYS_INLINE void block(Result& encoded, ResultState& state, const uint8_t* src) + { + using EncodedBlockSizeT = decltype(Codec::encoded_block_size()); + constexpr static const EncodedBlockSizeT SymbolIndex = static_cast(I - 1); + + enc().template block(encoded, state, src); + data::put(encoded, state, CodecVariant::symbol(Codec::template index(src))); + } + + // Tail encoding: Go from 0 until (runtime) num_symbols, append a symbol for each iteration. + template + static CPPCODEC_ALWAYS_INLINE void tail( + Result& encoded, ResultState& state, const uint8_t* src, EncodedBlockSizeT num_symbols) + { + constexpr static const EncodedBlockSizeT SymbolIndex = Codec::encoded_block_size() - I; + constexpr static const EncodedBlockSizeT NumSymbols = SymbolIndex + static_cast(1); + + if (num_symbols == NumSymbols) { + data::put(encoded, state, CodecVariant::symbol(Codec::template index_last(src))); + return; + } + data::put(encoded, state, CodecVariant::symbol(Codec::template index(src))); + enc().template tail(encoded, state, src, num_symbols); + } +}; + +template<> // terminating specialization +struct enc<0> { + template + static CPPCODEC_ALWAYS_INLINE void block(Result&, ResultState&, const uint8_t*) { } + + template + static CPPCODEC_ALWAYS_INLINE void tail(Result&, ResultState&, const uint8_t*, EncodedBlockSizeT) + { + abort(); // Not reached: block() should be called if num_symbols == block size, not tail(). + } +}; + +template +template +inline void stream_codec::encode( + Result& encoded_result, ResultState& state, + const uint8_t* src, size_t src_size) +{ + using encoder = enc; + + const uint8_t* src_end = src + src_size; + + if (src_size >= Codec::binary_block_size()) { + src_end -= Codec::binary_block_size(); + + for (; src <= src_end; src += Codec::binary_block_size()) { + encoder::template block(encoded_result, state, src); + } + src_end += Codec::binary_block_size(); + } + + if (src_end > src) { + auto remaining_src_len = src_end - src; + if (!remaining_src_len || remaining_src_len >= Codec::binary_block_size()) { + abort(); + return; + } + + auto num_symbols = Codec::num_encoded_tail_symbols( + static_cast(remaining_src_len)); + + encoder::template tail(encoded_result, state, src, num_symbols); + + padder::template pad( + encoded_result, state, Codec::encoded_block_size() - num_symbols); + } +} + +// Range & lookup table generation, see +// http://stackoverflow.com/questions/13313980/populate-an-array-using-constexpr-at-compile-time +// and http://cplusadd.blogspot.ca/2013/02/c11-compile-time-lookup-tablearray-with.html + +template struct seq {}; + +template +struct gen_seq : gen_seq { + // Clang up to 3.6 has a limit of 256 for template recursion, + // so pass a few more symbols at once to make it work. + static_assert(N % 4 == 0, "I must be divisible by 4 to eventually end at 0"); +}; +template +struct gen_seq<0, Is...> : seq {}; + +template +struct lookup_table_t { + alphabet_index_t lookup[N]; + static constexpr size_t size = N; +}; + +template +constexpr lookup_table_t make_lookup_table(seq, LambdaType value_for_index) { + return { { value_for_index(Is)... } }; +} + +template +constexpr lookup_table_t make_lookup_table(LambdaType evalFunc) { + return make_lookup_table(gen_seq(), evalFunc); +} + +// CodecVariant::symbol() provides a symbol for an index. +// Use recursive templates to get the inverse lookup table for fast decoding. + +template +static CPPCODEC_ALWAYS_INLINE constexpr size_t num_possible_values() +{ + return static_cast( + static_cast((std::numeric_limits::max)()) + - static_cast((std::numeric_limits::min)()) + 1); +} + +template +struct index_if_in_alphabet { + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t for_symbol(char symbol) + { + return (CodecVariant::symbol( + static_cast(CodecVariant::alphabet_size() - I)) == symbol) + ? static_cast(CodecVariant::alphabet_size() - I) + : index_if_in_alphabet::for_symbol(symbol); + } +}; +template +struct index_if_in_alphabet { // terminating specialization + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t for_symbol(char) + { + return InvalidIdx; + } +}; + +template +struct padding_searcher { + static CPPCODEC_ALWAYS_INLINE constexpr bool exists_padding_symbol() + { + // Clang up to 3.6 has a limit of 256 for template recursion, + // so pass a few more symbols at once to make it work. + static_assert(I % 4 == 0, "I must be divisible by 4 to eventually end at 0"); + + return CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 4)) + || CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 3)) + || CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 2)) + || CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 1)) + || padding_searcher::exists_padding_symbol(); + } +}; +template +struct padding_searcher { // terminating specialization + static CPPCODEC_ALWAYS_INLINE constexpr bool exists_padding_symbol() { return false; } +}; + +template +struct alphabet_index_info +{ + static constexpr const size_t num_possible_symbols = num_possible_values(); + + static constexpr const alphabet_index_t padding_idx = 1 << 8; + static constexpr const alphabet_index_t invalid_idx = 1 << 9; + static constexpr const alphabet_index_t eof_idx = 1 << 10; + static constexpr const alphabet_index_t stop_character_mask = static_cast(~0xFFu); + + static constexpr const bool padding_allowed = padding_searcher< + CodecVariant, num_possible_symbols>::exists_padding_symbol(); + + static CPPCODEC_ALWAYS_INLINE constexpr bool allows_padding() + { + return padding_allowed; + } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding(alphabet_index_t idx) + { + return allows_padding() ? (idx == padding_idx) : false; + } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_invalid(alphabet_index_t idx) { return idx == invalid_idx; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof(alphabet_index_t idx) { return idx == eof_idx; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_stop_character(alphabet_index_t idx) + { + return (idx & stop_character_mask) != 0; + } + +private: + static CPPCODEC_ALWAYS_INLINE constexpr + alphabet_index_t valid_index_or(alphabet_index_t a, alphabet_index_t b) + { + return a == invalid_idx ? b : a; + } + + using idx_if_in_alphabet = index_if_in_alphabet< + CodecVariant, invalid_idx, CodecVariant::alphabet_size()>; + + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t index_of(char symbol) + { + return valid_index_or(idx_if_in_alphabet::for_symbol(symbol), + CodecVariant::is_eof_symbol(symbol) ? eof_idx + : CodecVariant::is_padding_symbol(symbol) ? padding_idx + : invalid_idx); + } + + // GCC <= 4.9 has a bug with retaining constexpr when passing a function pointer. + // To get around this, we'll create a callable with operator() and pass that one. + // Unfortunately, MSVC prior to VS 2017 (for MinSizeRel or Release builds) + // chokes on this by compiling the project in 20 minutes instead of seconds. + // So let's define two separate variants and remove the old GCC one whenever we + // decide not to support GCC < 5.0 anymore. +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 + struct index_at { + CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t operator()(size_t symbol) const { + return index_of(CodecVariant::normalized_symbol(static_cast(symbol))); + } + }; +#else + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t index_at(size_t symbol) + { + return index_of(CodecVariant::normalized_symbol(static_cast(symbol))); + } +#endif + +public: + struct lookup { + static CPPCODEC_ALWAYS_INLINE alphabet_index_t for_symbol(char symbol) + { +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 + static constexpr const auto t = make_lookup_table(index_at()); +#else + static constexpr const auto t = make_lookup_table(&index_at); +#endif + static_assert(t.size == num_possible_symbols, + "lookup table must cover each possible (character) symbol"); + return t.lookup[static_cast(symbol)]; + } + }; +}; + +// +// At long last! The actual decode/encode functions. + +template +template +inline void stream_codec::decode( + Result& binary_result, ResultState& state, + const char* src_encoded, size_t src_size) +{ + using alphabet_index_lookup = typename alphabet_index_info::lookup; + const char* src = src_encoded; + const char* src_end = src + src_size; + + alphabet_index_t alphabet_indexes[Codec::encoded_block_size()] = {}; + alphabet_indexes[0] = alphabet_index_info::eof_idx; + + alphabet_index_t* const alphabet_index_start = &alphabet_indexes[0]; + alphabet_index_t* const alphabet_index_end = &alphabet_indexes[Codec::encoded_block_size()]; + alphabet_index_t* alphabet_index_ptr = &alphabet_indexes[0]; + + while (src < src_end) { + if (CodecVariant::should_ignore(*src)) { + ++src; + continue; + } + *alphabet_index_ptr = alphabet_index_lookup::for_symbol(*src); + if (alphabet_index_info::is_stop_character(*alphabet_index_ptr)) { + break; + } + ++src; + ++alphabet_index_ptr; + + if (alphabet_index_ptr == alphabet_index_end) { + Codec::decode_block(binary_result, state, alphabet_indexes); + alphabet_index_ptr = alphabet_index_start; + } + } + + if (alphabet_index_info::is_invalid(*alphabet_index_ptr)) { + throw symbol_error(*src); + } + ++src; + + alphabet_index_t* last_index_ptr = alphabet_index_ptr; + if (alphabet_index_info::is_padding(*last_index_ptr)) { + if (last_index_ptr == alphabet_index_start) { + // Don't accept padding at the start of a block. + // The encoder should have omitted that padding altogether. + throw padding_error(); + } + // We're in here because we just read a (first) padding character. Try to read more. + // Count with last_index_ptr, but store in alphabet_index_ptr so we don't + // overflow the array in case the input data is too long. + ++last_index_ptr; + while (src < src_end) { + *alphabet_index_ptr = alphabet_index_lookup::for_symbol(*(src++)); + + if (alphabet_index_info::is_eof(*alphabet_index_ptr)) { + *alphabet_index_ptr = alphabet_index_info::padding_idx; + break; + } + if (!alphabet_index_info::is_padding(*alphabet_index_ptr)) { + throw padding_error(); + } + + ++last_index_ptr; + if (last_index_ptr > alphabet_index_end) { + throw padding_error(); + } + } + } + + if (last_index_ptr != alphabet_index_start) { + if ((CodecVariant::requires_padding() + || alphabet_index_info::is_padding(*alphabet_index_ptr) + ) && last_index_ptr != alphabet_index_end) + { + // If the input is not a multiple of the block size then the input is incorrect. + throw padding_error(); + } + if (alphabet_index_ptr >= alphabet_index_end) { + abort(); + return; + } + Codec::decode_tail(binary_result, state, alphabet_indexes, + static_cast(alphabet_index_ptr - alphabet_index_start)); + } +} + +template +inline constexpr size_t stream_codec::encoded_size(size_t binary_size) noexcept +{ + using C = Codec; + + // constexpr rules make this a lot harder to read than it actually is. + return CodecVariant::generates_padding() + // With padding, the encoded size is a multiple of the encoded block size. + // To calculate that, round the binary size up to multiple of the binary block size, + // then convert to encoded by multiplying with { base32: 8/5, base64: 4/3 }. + ? (binary_size + (C::binary_block_size() - 1) + - ((binary_size + (C::binary_block_size() - 1)) % C::binary_block_size())) + * C::encoded_block_size() / C::binary_block_size() + // No padding: only pad to the next multiple of 5 bits, i.e. at most a single extra byte. + : (binary_size * C::encoded_block_size() / C::binary_block_size()) + + (((binary_size * C::encoded_block_size()) % C::binary_block_size()) ? 1 : 0); +} + +template +inline constexpr size_t stream_codec::decoded_max_size(size_t encoded_size) noexcept +{ + using C = Codec; + + return CodecVariant::requires_padding() + ? (encoded_size / C::encoded_block_size() * C::binary_block_size()) + : (encoded_size / C::encoded_block_size() * C::binary_block_size()) + + ((encoded_size % C::encoded_block_size()) + * C::binary_block_size() / C::encoded_block_size()); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_STREAM_CODEC diff --git a/include/Third_Lib/cppcodec/hex_default_lower.hpp b/include/Third_Lib/cppcodec/hex_default_lower.hpp new file mode 100644 index 0000000..3b10675 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_default_lower.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_HEX_DEFAULT_LOWER +#define CPPCODEC_HEX_DEFAULT_LOWER + +#include "hex_lower.hpp" + +using hex = cppcodec::hex_lower; + +#endif // CPPCODEC_HEX_DEFAULT_LOWER diff --git a/include/Third_Lib/cppcodec/hex_default_upper.hpp b/include/Third_Lib/cppcodec/hex_default_upper.hpp new file mode 100644 index 0000000..a960f02 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_default_upper.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_HEX_DEFAULT_UPPER +#define CPPCODEC_HEX_DEFAULT_UPPER + +#include "hex_upper.hpp" + +using hex = cppcodec::hex_upper; + +#endif // CPPCODEC_HEX_DEFAULT_UPPER diff --git a/include/Third_Lib/cppcodec/hex_lower.hpp b/include/Third_Lib/cppcodec/hex_lower.hpp new file mode 100644 index 0000000..36ad583 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_lower.hpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_HEX_LOWER +#define CPPCODEC_HEX_LOWER + +#include "detail/codec.hpp" +#include "detail/hex.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char hex_lower_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // at index 10 + 'a', 'b', 'c', 'd', 'e', 'f' +}; + +class hex_lower +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(hex_lower_alphabet) == 16, "hex alphabet must have 16 values"); + return sizeof(hex_lower_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t index) + { + return hex_lower_alphabet[index]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Hex decoding is always case-insensitive (even in RFC 4648), the question + // is only for encoding whether to use upper-case or lower-case letters. + return (c >= 'A' && c <= 'F') ? (c - 'A' + 'a') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + // FIXME: doesn't require padding, but requires a multiple of the encoded block size (2) + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char) { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // Sometimes hex strings include whitespace, but this variant forbids it. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using hex_lower = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_HEX_LOWER diff --git a/include/Third_Lib/cppcodec/hex_upper.hpp b/include/Third_Lib/cppcodec/hex_upper.hpp new file mode 100644 index 0000000..9b811c6 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_upper.hpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_HEX_UPPER +#define CPPCODEC_HEX_UPPER + +#include "detail/codec.hpp" +#include "detail/hex.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char hex_upper_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +class hex_upper +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(hex_upper_alphabet) == 16, "hex alphabet must have 16 values"); + return sizeof(hex_upper_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t index) + { + return hex_upper_alphabet[index]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Hex decoding is always case-insensitive (even in RFC 4648), the question + // is only for encoding whether to use upper-case or lower-case letters. + return (c >= 'a' && c <= 'f') ? (c - 'a' + 'A') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + // FIXME: doesn't require padding, but requires a multiple of the encoded block size (2) + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char) { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // Sometimes hex strings include whitespace, but this variant forbids it. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using hex_upper = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_HEX_UPPER diff --git a/include/Third_Lib/cppcodec/parse_error.hpp b/include/Third_Lib/cppcodec/parse_error.hpp new file mode 100644 index 0000000..97438ad --- /dev/null +++ b/include/Third_Lib/cppcodec/parse_error.hpp @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * 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. + */ + +#ifndef CPPCODEC_PARSE_ERROR +#define CPPCODEC_PARSE_ERROR + +#include +#include + +namespace cppcodec { + +namespace detail { +// <*stream> headers include a lot of code and noticeably increase compile times. +// The only thing we want from them really is a char-to-string conversion. +// That's easy to implement with many less lines of code, so let's do it ourselves. +template +static void uctoa(unsigned char n, char (&s)[N]) +{ + static_assert(N >= 4, "need at least 4 bytes to convert an unsigned char to string safely"); + int i = sizeof(s) - 1; + int num_chars = 1; + s[i--] = '\0'; + do { // generate digits in reverse order + s[i--] = n % 10 + '0'; // get next digit + ++num_chars; + } while ((n /= 10) > 0); // delete it + + if (num_chars == sizeof(s)) { + return; + } + for (i = 0; i < num_chars; ++i) { // move chars to front of string + s[i] = s[i + (sizeof(s) - num_chars)]; + } +} +} // end namespace detail + + +class parse_error : public std::domain_error +{ +public: + using std::domain_error::domain_error; +}; + +// Avoids memory allocation, so it can be used in constexpr functions. +class symbol_error : public parse_error +{ +public: + symbol_error(char c) + : parse_error(symbol_error::make_error_message(c)) + , m_symbol(c) + { + } + + symbol_error(const symbol_error&) = default; + + char symbol() const noexcept { return m_symbol; } + +private: + static std::string make_error_message(char c) + { + char s[4]; + detail::uctoa(*reinterpret_cast(&c), s); + return std::string("parse error: character [") + &(s[0]) + " '" + c + "'] out of bounds"; + } + +private: + char m_symbol; +}; + +class invalid_input_length : public parse_error +{ +public: + using parse_error::parse_error; +}; + +class padding_error : public invalid_input_length +{ +public: + padding_error() + : invalid_input_length("parse error: codec expects padded input string but padding was invalid") + { + } + + padding_error(const padding_error&) = default; +}; + +} // namespace cppcodec + +#endif // CPPCODEC_PARSE_ERROR diff --git a/include/Third_Lib/fmt/core.h b/include/Third_Lib/fmt/core.h new file mode 100644 index 0000000..5e829fd --- /dev/null +++ b/include/Third_Lib/fmt/core.h @@ -0,0 +1,2744 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CORE_H_ +#define FMT_CORE_H_ + +#include // INT_MAX +#include // std::FILE +#include +#include +#include +#include + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 70104 + +#ifdef __clang__ +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +#else +# define FMT_GCC_VERSION 0 +# define FMT_GCC_PRAGMA(arg) +#endif + +#if defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#else +# define FMT_ICC_VERSION 0 +#endif + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION +#else +# define FMT_HAS_GXX_CXX11 0 +#endif + +// Check if constexpr std::char_traits<>::compare,length is supported. +#if defined(__GLIBCXX__) +# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ + _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#elif defined(_LIBCPP_VERSION) +# if __cplusplus >= 201703L && _LIBCPP_VERSION >= 4000 +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#elif defined(_MSC_VER) +# if _MSVC_LANG >= 201703L && _MSC_VER >= 1914 +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#endif +#ifndef FMT_CONSTEXPR_CHAR_TRAITS +# define FMT_CONSTEXPR_CHAR_TRAITS +#endif + +#ifdef __NVCC__ +# define FMT_NVCC __NVCC__ +#else +# define FMT_NVCC 0 +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +#else +# define FMT_MSC_VER 0 +# define FMT_MSC_WARNING(...) +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#if defined(__has_include) && !defined(__INTELLISENSE__) && \ + (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600) +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ + (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ + (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +// Check if relaxed C++14 constexpr is supported. +// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +#ifndef FMT_USE_CONSTEXPR +# define FMT_USE_CONSTEXPR \ + (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ + (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ + !FMT_NVCC && !FMT_ICC_VERSION +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +# define FMT_CONSTEXPR_DECL constexpr +#else +# define FMT_CONSTEXPR +# define FMT_CONSTEXPR_DECL +#endif + +#ifndef FMT_OVERRIDE +# if FMT_HAS_FEATURE(cxx_override_control) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_OVERRIDE override +# else +# define FMT_OVERRIDE +# endif +#endif + +// Check if exceptions are disabled. +#ifndef FMT_EXCEPTIONS +# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ + FMT_MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +# else +# define FMT_EXCEPTIONS 1 +# endif +#endif + +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_DETECTED_NOEXCEPT noexcept +# define FMT_HAS_CXX11_NOEXCEPT 1 +#else +# define FMT_DETECTED_NOEXCEPT throw() +# define FMT_HAS_CXX11_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +# else +# define FMT_NOEXCEPT +# endif +#endif + +// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code +// warnings. +#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ + !FMT_NVCC +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif +#endif + +#ifndef FMT_DEPRECATED +# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 +# define FMT_DEPRECATED [[deprecated]] +# else +# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) +# define FMT_DEPRECATED __attribute__((deprecated)) +# elif FMT_MSC_VER +# define FMT_DEPRECATED __declspec(deprecated) +# else +# define FMT_DEPRECATED /* deprecated */ +# endif +# endif +#endif + +// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. +#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC +# define FMT_DEPRECATED_ALIAS +#else +# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED +#endif + +#ifndef FMT_INLINE +# if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_INLINE inline __attribute__((always_inline)) +# else +# define FMT_INLINE inline +# endif +#endif + +#ifndef FMT_USE_INLINE_NAMESPACES +# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ + (FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED)) +# define FMT_USE_INLINE_NAMESPACES 1 +# else +# define FMT_USE_INLINE_NAMESPACES 0 +# endif +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# if FMT_USE_INLINE_NAMESPACES +# define FMT_INLINE_NAMESPACE inline namespace +# define FMT_END_NAMESPACE \ + } \ + } +# else +# define FMT_INLINE_NAMESPACE namespace +# define FMT_END_NAMESPACE \ + } \ + using namespace v7; \ + } +# endif +# define FMT_BEGIN_NAMESPACE \ + namespace fmt { \ + FMT_INLINE_NAMESPACE v7 { +#endif + +#ifndef FMT_MODULE_EXPORT +# define FMT_MODULE_EXPORT +#endif +#ifndef FMT_MODULE_EXPORT_BEGIN +# define FMT_MODULE_EXPORT_BEGIN +#endif +#ifndef FMT_MODULE_EXPORT_END +# define FMT_MODULE_EXPORT_END +#endif +#ifndef FMT_BEGIN_DETAIL_NAMESPACE +# define FMT_BEGIN_DETAIL_NAMESPACE \ + namespace detail { +#endif +#ifndef FMT_END_DETAIL_NAMESPACE +# define FMT_END_DETAIL_NAMESPACE \ + } +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#else +# define FMT_CLASS_API +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#if FMT_GCC_VERSION +# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) +#else +# define FMT_GCC_VISIBILITY_HIDDEN +#endif + +// libc++ supports string_view in pre-c++17. +#if (FMT_HAS_INCLUDE() && \ + (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +# include +# define FMT_USE_STRING_VIEW +#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L +# include +# define FMT_USE_EXPERIMENTAL_STRING_VIEW +#endif + +#ifndef FMT_UNICODE +# define FMT_UNICODE !FMT_MSC_VER +#endif + +#ifndef FMT_COMPILE_TIME_CHECKS +# define FMT_COMPILE_TIME_CHECKS 0 +#endif + +#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +# if defined(__cpp_nontype_template_args) && \ + ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \ + __cpp_nontype_template_args >= 201911L) +# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1 +# else +# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0 +# endif +#endif + +// Enable minimal optimizations for more compact code in debug mode. +FMT_GCC_PRAGMA("GCC push_options") +#ifndef __OPTIMIZE__ +FMT_GCC_PRAGMA("GCC optimize(\"Og\")") +#endif + +FMT_BEGIN_NAMESPACE + FMT_MODULE_EXPORT_BEGIN + +// Implementations of enable_if_t and other metafunctions for older systems. + template + using enable_if_t = typename std::enable_if::type; + template + using conditional_t = typename std::conditional::type; + template using bool_constant = std::integral_constant; + template + using remove_reference_t = typename std::remove_reference::type; + template + using remove_const_t = typename std::remove_const::type; + template + using remove_cvref_t = typename std::remove_cv>::type; + template struct type_identity { using type = T; }; + template using type_identity_t = typename type_identity::type; + + struct monostate {}; + +// An enable_if helper to be used in template parameters which results in much +// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed +// to workaround a bug in MSVC 2019 (see #1140 and #1186). +#ifdef FMT_DOC +# define FMT_ENABLE_IF(...) +#else +# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 +#endif + + FMT_BEGIN_DETAIL_NAMESPACE + + constexpr FMT_INLINE bool is_constant_evaluated() FMT_NOEXCEPT { +#ifdef __cpp_lib_is_constant_evaluated + return std::is_constant_evaluated(); +#else + return false; +#endif + } + +// A helper function to suppress "conditional expression is constant" warnings. + template constexpr T const_check(T value) { return value; } + + FMT_NORETURN FMT_API void assert_fail(const char* file, int line, + const char* message); + +#ifndef FMT_ASSERT +# ifdef NDEBUG + // FMT_ASSERT is not empty to avoid -Werror=empty-body. +# define FMT_ASSERT(condition, message) ((void)0) +# else +# define FMT_ASSERT(condition, message) \ + ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ + ? (void)0 \ + : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message))) +# endif +#endif + +#if defined(FMT_USE_STRING_VIEW) + template using std_string_view = std::basic_string_view; +#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) + template + using std_string_view = std::experimental::basic_string_view; +#else + template struct std_string_view {}; +#endif + +#ifdef FMT_USE_INT128 + // Do nothing. +#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ + !(FMT_CLANG_VERSION && FMT_MSC_VER) +# define FMT_USE_INT128 1 + using int128_t = __int128_t; + using uint128_t = __uint128_t; +#else +# define FMT_USE_INT128 0 +#endif +#if !FMT_USE_INT128 + struct int128_t {}; +struct uint128_t {}; +#endif + +// Casts a nonnegative integer to unsigned. + template + FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast::type>(value); + } + + FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5"; + + template constexpr bool is_unicode() { + return FMT_UNICODE || sizeof(Char) != 1 || + (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5); + } + + FMT_END_DETAIL_NAMESPACE + +/** + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. ``fmt::basic_string_view`` is used for format strings even + if ``std::string_view`` is available to prevent issues when a library is + compiled with a different ``-std`` option than the client code (which is not + recommended). + */ + template class basic_string_view { + private: + const Char* data_; + size_t size_; + + public: + using value_type = Char; + using iterator = const Char*; + + constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {} + + /** Constructs a string reference object from a C string and a size. */ + constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT + : data_(s), + size_(count) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + \endrst + */ + FMT_CONSTEXPR_CHAR_TRAITS + FMT_INLINE + basic_string_view(const Char* s) : data_(s) { + if (detail::const_check(std::is_same::value && + !detail::is_constant_evaluated())) + size_ = std::strlen(reinterpret_cast(s)); + else + size_ = std::char_traits::length(s); + } + + /** Constructs a string reference from a ``std::basic_string`` object. */ + template + FMT_CONSTEXPR basic_string_view( + const std::basic_string& s) FMT_NOEXCEPT + : data_(s.data()), + size_(s.size()) {} + + template >::value)> + FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()), + size_(s.size()) {} + + /** Returns a pointer to the string data. */ + constexpr const Char* data() const { return data_; } + + /** Returns the string size. */ + constexpr size_t size() const { return size_; } + + constexpr iterator begin() const { return data_; } + constexpr iterator end() const { return data_ + size_; } + + constexpr const Char& operator[](size_t pos) const { return data_[pos]; } + + FMT_CONSTEXPR void remove_prefix(size_t n) { + data_ += n; + size_ -= n; + } + + // Lexicographically compare this string reference to other. + FMT_CONSTEXPR_CHAR_TRAITS int compare(basic_string_view other) const { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + FMT_CONSTEXPR_CHAR_TRAITS friend bool operator==(basic_string_view lhs, + basic_string_view rhs) { + return lhs.compare(rhs) == 0; + } + friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) != 0; + } + friend bool operator<(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) < 0; + } + friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) <= 0; + } + friend bool operator>(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) >= 0; + } + }; + + using string_view = basic_string_view; + using wstring_view = basic_string_view; + +/** Specifies if ``T`` is a character type. Can be specialized by users. */ + template struct is_char : std::false_type {}; + template <> struct is_char : std::true_type {}; + template <> struct is_char : std::true_type {}; + +/** + \rst + Returns a string view of `s`. In order to add custom string type support to + {fmt} provide an overload of `to_string_view` for it in the same namespace as + the type for the argument-dependent lookup to work. + + **Example**:: + + namespace my_ns { + inline string_view to_string_view(const my_string& s) { + return {s.data(), s.length()}; + } + } + std::string message = fmt::format(my_string("The answer is {}"), 42); + \endrst + */ + template ::value)> + FMT_INLINE basic_string_view to_string_view(const Char* s) { + return s; + } + + template + inline basic_string_view to_string_view( + const std::basic_string& s) { + return s; + } + + template + constexpr basic_string_view to_string_view(basic_string_view s) { + return s; + } + + template >::value)> + inline basic_string_view to_string_view(detail::std_string_view s) { + return s; + } + +// A base class for compile-time strings. It is defined in the fmt namespace to +// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42). + struct compile_string {}; + + template + struct is_compile_string : std::is_base_of {}; + + template ::value)> + constexpr basic_string_view to_string_view(const S& s) { + return s; + } + + FMT_BEGIN_DETAIL_NAMESPACE + + void to_string_view(...); + using fmt::v7::to_string_view; + +// Specifies whether S is a string type convertible to fmt::basic_string_view. +// It should be a constexpr function but MSVC 2017 fails to compile it in +// enable_if and MSVC 2015 fails to compile it as an alias template. + template + struct is_string : std::is_class()))> { + }; + + template struct char_t_impl {}; + template struct char_t_impl::value>> { + using result = decltype(to_string_view(std::declval())); + using type = typename result::value_type; + }; + +// Reports a compile-time error if S is not a valid format string. + template ::value)> + FMT_INLINE void check_format_string(const S&) { +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert(is_compile_string::value, + "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " + "FMT_STRING."); +#endif + } + template ::value)> + void check_format_string(S); + + struct error_handler { + constexpr error_handler() = default; + constexpr error_handler(const error_handler&) = default; + + // This function is intentionally not constexpr to give a compile-time error. + FMT_NORETURN FMT_API void on_error(const char* message); + }; + + FMT_END_DETAIL_NAMESPACE + +/** String's character type. */ + template using char_t = typename detail::char_t_impl::type; + +/** + \rst + Parsing context consisting of a format string range being parsed and an + argument counter for automatic indexing. + + You can use one of the following type aliases for common character types: + + +-----------------------+-------------------------------------+ + | Type | Definition | + +=======================+=====================================+ + | format_parse_context | basic_format_parse_context | + +-----------------------+-------------------------------------+ + | wformat_parse_context | basic_format_parse_context | + +-----------------------+-------------------------------------+ + \endrst + */ + template + class basic_format_parse_context : private ErrorHandler { + private: + basic_string_view format_str_; + int next_arg_id_; + + public: + using char_type = Char; + using iterator = typename basic_string_view::iterator; + + explicit constexpr basic_format_parse_context( + basic_string_view format_str, ErrorHandler eh = {}, + int next_arg_id = 0) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {} + + /** + Returns an iterator to the beginning of the format string range being + parsed. + */ + constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); } + + /** + Returns an iterator past the end of the format string range being parsed. + */ + constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); } + + /** Advances the begin iterator to ``it``. */ + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(detail::to_unsigned(it - begin())); + } + + /** + Reports an error if using the manual argument indexing; otherwise returns + the next argument index and switches to the automatic indexing. + */ + FMT_CONSTEXPR int next_arg_id() { + // Don't check if the argument id is valid to avoid overhead and because it + // will be checked during formatting anyway. + if (next_arg_id_ >= 0) return next_arg_id_++; + on_error("cannot switch from manual to automatic argument indexing"); + return 0; + } + + /** + Reports an error if using the automatic argument indexing; otherwise + switches to the manual indexing. + */ + FMT_CONSTEXPR void check_arg_id(int) { + if (next_arg_id_ > 0) + on_error("cannot switch from automatic to manual argument indexing"); + else + next_arg_id_ = -1; + } + + FMT_CONSTEXPR void check_arg_id(basic_string_view) {} + + FMT_CONSTEXPR void on_error(const char* message) { + ErrorHandler::on_error(message); + } + + constexpr ErrorHandler error_handler() const { return *this; } + }; + + using format_parse_context = basic_format_parse_context; + using wformat_parse_context = basic_format_parse_context; + + template class basic_format_arg; + template class basic_format_args; + template class dynamic_format_arg_store; + +// A formatter for objects of type T. + template + struct formatter { + // A deleted default constructor indicates a disabled formatter. + formatter() = delete; + }; + +// DEPRECATED! +// Specifies if T has an enabled formatter specialization. A type can be +// formattable even if it doesn't have a formatter e.g. via a conversion. + template + using has_formatter = + std::is_constructible>; + +// Checks whether T is a container with contiguous storage. + template struct is_contiguous : std::false_type {}; + template + struct is_contiguous> : std::true_type {}; + + FMT_BEGIN_DETAIL_NAMESPACE + +// Extracts a reference to the container from back_insert_iterator. + template + inline Container& get_container(std::back_insert_iterator it) { + using bi_iterator = std::back_insert_iterator; + struct accessor : bi_iterator { + accessor(bi_iterator iter) : bi_iterator(iter) {} + using bi_iterator::container; + }; + return *accessor(it).container; + } + +/** + \rst + A contiguous memory buffer with an optional growing ability. It is an internal + class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. + \endrst + */ + template class buffer { + private: + T* ptr_; + size_t size_; + size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + FMT_MSC_WARNING(suppress : 26495) + buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} + + buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT + : ptr_(p), + size_(sz), + capacity_(cap) {} + + ~buffer() = default; + + /** Sets the buffer data and capacity. */ + void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + virtual void grow(size_t capacity) = 0; + + public: + using value_type = T; + using const_reference = const T&; + + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + T* begin() FMT_NOEXCEPT { return ptr_; } + T* end() FMT_NOEXCEPT { return ptr_ + size_; } + + const T* begin() const FMT_NOEXCEPT { return ptr_; } + const T* end() const FMT_NOEXCEPT { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + size_t size() const FMT_NOEXCEPT { return size_; } + + /** Returns the capacity of this buffer. */ + size_t capacity() const FMT_NOEXCEPT { return capacity_; } + + /** Returns a pointer to the buffer data. */ + T* data() FMT_NOEXCEPT { return ptr_; } + + /** Returns a pointer to the buffer data. */ + const T* data() const FMT_NOEXCEPT { return ptr_; } + + /** Clears this buffer. */ + void clear() { size_ = 0; } + + // Tries resizing the buffer to contain *count* elements. If T is a POD type + // the new elements may not be initialized. + void try_resize(size_t count) { + try_reserve(count); + size_ = count <= capacity_ ? count : capacity_; + } + + // Tries increasing the buffer capacity to *new_capacity*. It can increase the + // capacity by a smaller amount than requested but guarantees there is space + // for at least one additional element either by increasing the capacity or by + // flushing the buffer if it is full. + void try_reserve(size_t new_capacity) { + if (new_capacity > capacity_) grow(new_capacity); + } + + void push_back(const T& value) { + try_reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template void append(const U* begin, const U* end); + + template T& operator[](I index) { return ptr_[index]; } + template const T& operator[](I index) const { + return ptr_[index]; + } + }; + + struct buffer_traits { + explicit buffer_traits(size_t) {} + size_t count() const { return 0; } + size_t limit(size_t size) { return size; } + }; + + class fixed_buffer_traits { + private: + size_t count_ = 0; + size_t limit_; + + public: + explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} + size_t count() const { return count_; } + size_t limit(size_t size) { + size_t n = limit_ > count_ ? limit_ - count_ : 0; + count_ += size; + return size < n ? size : n; + } + }; + +// A buffer that writes to an output iterator when flushed. + template + class iterator_buffer final : public Traits, public buffer { + private: + OutputIt out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + void grow(size_t) final FMT_OVERRIDE { + if (this->size() == buffer_size) flush(); + } + void flush(); + + public: + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) + : Traits(n), buffer(data_, 0, buffer_size), out_(out) {} + ~iterator_buffer() { flush(); } + + OutputIt out() { + flush(); + return out_; + } + size_t count() const { return Traits::count() + this->size(); } + }; + + template class iterator_buffer final : public buffer { + protected: + void grow(size_t) final FMT_OVERRIDE {} + + public: + explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} + + T* out() { return &*this->end(); } + }; + +// A buffer that writes to a container with the contiguous storage. + template + class iterator_buffer, + enable_if_t::value, + typename Container::value_type>> + final : public buffer { + private: + Container& container_; + + protected: + void grow(size_t capacity) final FMT_OVERRIDE { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit iterator_buffer(Container& c) + : buffer(c.size()), container_(c) {} + explicit iterator_buffer(std::back_insert_iterator out, size_t = 0) + : iterator_buffer(get_container(out)) {} + std::back_insert_iterator out() { + return std::back_inserter(container_); + } + }; + +// A buffer that counts the number of code units written discarding the output. + template class counting_buffer final : public buffer { + private: + enum { buffer_size = 256 }; + T data_[buffer_size]; + size_t count_ = 0; + + protected: + void grow(size_t) final FMT_OVERRIDE { + if (this->size() != buffer_size) return; + count_ += this->size(); + this->clear(); + } + + public: + counting_buffer() : buffer(data_, 0, buffer_size) {} + + size_t count() { return count_ + this->size(); } + }; + +// An output iterator that appends to the buffer. +// It is used to reduce symbol sizes for the common case. + template + class buffer_appender : public std::back_insert_iterator> { + using base = std::back_insert_iterator>; + + public: + using std::back_insert_iterator>::back_insert_iterator; + buffer_appender(base it) : base(it) {} + using _Unchecked_type = buffer_appender; // Mark iterator as checked. + + buffer_appender& operator++() { + base::operator++(); + return *this; + } + + buffer_appender operator++(int) { + buffer_appender tmp = *this; + ++*this; + return tmp; + } + }; + +// Maps an output iterator into a buffer. + template + iterator_buffer get_buffer(OutputIt); + template buffer& get_buffer(buffer_appender); + + template OutputIt get_buffer_init(OutputIt out) { + return out; + } + template buffer& get_buffer_init(buffer_appender out) { + return get_container(out); + } + + template + auto get_iterator(Buffer& buf) -> decltype(buf.out()) { + return buf.out(); + } + template buffer_appender get_iterator(buffer& buf) { + return buffer_appender(buf); + } + + template + struct fallback_formatter { + fallback_formatter() = delete; + }; + +// Specifies if T has an enabled fallback_formatter specialization. + template + using has_fallback_formatter = + std::is_constructible>; + + struct view {}; + + template struct named_arg : view { + const Char* name; + const T& value; + named_arg(const Char* n, const T& v) : name(n), value(v) {} + }; + + template struct named_arg_info { + const Char* name; + int id; + }; + + template + struct arg_data { + // args_[0].named_args points to named_args_ to avoid bloating format_args. + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; + named_arg_info named_args_[NUM_NAMED_ARGS]; + + template + arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} + arg_data(const arg_data& other) = delete; + const T* args() const { return args_ + 1; } + named_arg_info* named_args() { return named_args_; } + }; + + template + struct arg_data { + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; + + template + FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} + FMT_CONSTEXPR FMT_INLINE const T* args() const { return args_; } + FMT_CONSTEXPR FMT_INLINE std::nullptr_t named_args() { return nullptr; } + }; + + template + inline void init_named_args(named_arg_info*, int, int) {} + + template struct is_named_arg : std::false_type {}; + template struct is_statically_named_arg : std::false_type {}; + + template + struct is_named_arg> : std::true_type {}; + + template ::value)> + void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T&, const Tail&... args) { + init_named_args(named_args, arg_count + 1, named_arg_count, args...); + } + + template ::value)> + void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T& arg, const Tail&... args) { + named_args[named_arg_count++] = {arg.name, arg_count}; + init_named_args(named_args, arg_count + 1, named_arg_count, args...); + } + + template + FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, + const Args&...) {} + + template constexpr size_t count() { return B ? 1 : 0; } + template constexpr size_t count() { + return (B1 ? 1 : 0) + count(); + } + + template constexpr size_t count_named_args() { + return count::value...>(); + } + + enum class type { + none_type, + // Integer types should go first, + int_type, + uint_type, + long_long_type, + ulong_long_type, + int128_type, + uint128_type, + bool_type, + char_type, + last_integer_type = char_type, + // followed by floating-point types. + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + cstring_type, + string_type, + pointer_type, + custom_type + }; + +// Maps core type T to the corresponding type enum constant. + template + struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant \ + : std::integral_constant {} + + FMT_TYPE_CONSTANT(int, int_type); + FMT_TYPE_CONSTANT(unsigned, uint_type); + FMT_TYPE_CONSTANT(long long, long_long_type); + FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); + FMT_TYPE_CONSTANT(int128_t, int128_type); + FMT_TYPE_CONSTANT(uint128_t, uint128_type); + FMT_TYPE_CONSTANT(bool, bool_type); + FMT_TYPE_CONSTANT(Char, char_type); + FMT_TYPE_CONSTANT(float, float_type); + FMT_TYPE_CONSTANT(double, double_type); + FMT_TYPE_CONSTANT(long double, long_double_type); + FMT_TYPE_CONSTANT(const Char*, cstring_type); + FMT_TYPE_CONSTANT(basic_string_view, string_type); + FMT_TYPE_CONSTANT(const void*, pointer_type); + + constexpr bool is_integral_type(type t) { + return t > type::none_type && t <= type::last_integer_type; + } + + constexpr bool is_arithmetic_type(type t) { + return t > type::none_type && t <= type::last_numeric_type; + } + + template struct string_value { + const Char* data; + size_t size; + }; + + template struct named_arg_value { + const named_arg_info* data; + size_t size; + }; + + template struct custom_value { + using parse_context = typename Context::parse_context_type; + const void* value; + void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); + }; + +// A formatting argument value. + template class value { + public: + using char_type = typename Context::char_type; + + union { + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + int128_t int128_value; + uint128_t uint128_value; + bool bool_value; + char_type char_value; + float float_value; + double double_value; + long double long_double_value; + const void* pointer; + string_value string; + custom_value custom; + named_arg_value named_args; + }; + + constexpr FMT_INLINE value(int val = 0) : int_value(val) {} + constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} + constexpr FMT_INLINE value(long long val) : long_long_value(val) {} + constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} + FMT_INLINE value(int128_t val) : int128_value(val) {} + FMT_INLINE value(uint128_t val) : uint128_value(val) {} + FMT_INLINE value(float val) : float_value(val) {} + FMT_INLINE value(double val) : double_value(val) {} + FMT_INLINE value(long double val) : long_double_value(val) {} + constexpr FMT_INLINE value(bool val) : bool_value(val) {} + constexpr FMT_INLINE value(char_type val) : char_value(val) {} + FMT_CONSTEXPR FMT_INLINE value(const char_type* val) { + string.data = val; + if (is_constant_evaluated()) string.size = {}; + } + FMT_CONSTEXPR FMT_INLINE value(basic_string_view val) { + string.data = val.data(); + string.size = val.size(); + } + FMT_INLINE value(const void* val) : pointer(val) {} + FMT_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + template FMT_INLINE value(const T& val) { + custom.value = &val; + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + custom.format = format_custom_arg< + T, conditional_t::value, + typename Context::template formatter_type, + fallback_formatter>>; + } + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(const void* arg, + typename Context::parse_context_type& parse_ctx, + Context& ctx) { + Formatter f; + parse_ctx.advance_to(f.parse(parse_ctx)); + ctx.advance_to(f.format(*static_cast(arg), ctx)); + } + }; + + template + FMT_CONSTEXPR basic_format_arg make_arg(const T& value); + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. + enum { long_short = sizeof(long) == sizeof(int) }; + using long_type = conditional_t; + using ulong_type = conditional_t; + + struct unformattable {}; + +// Maps formatting arguments to core types. + template struct arg_mapper { + using char_type = typename Context::char_type; + + FMT_CONSTEXPR FMT_INLINE int map(signed char val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned char val) { return val; } + FMT_CONSTEXPR FMT_INLINE int map(short val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned short val) { return val; } + FMT_CONSTEXPR FMT_INLINE int map(int val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned val) { return val; } + FMT_CONSTEXPR FMT_INLINE long_type map(long val) { return val; } + FMT_CONSTEXPR FMT_INLINE ulong_type map(unsigned long val) { return val; } + FMT_CONSTEXPR FMT_INLINE long long map(long long val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned long long map(unsigned long long val) { + return val; + } + FMT_CONSTEXPR FMT_INLINE int128_t map(int128_t val) { return val; } + FMT_CONSTEXPR FMT_INLINE uint128_t map(uint128_t val) { return val; } + FMT_CONSTEXPR FMT_INLINE bool map(bool val) { return val; } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE char_type map(T val) { + static_assert( + std::is_same::value || std::is_same::value, + "mixing character types is disallowed"); + return val; + } + + FMT_CONSTEXPR FMT_INLINE float map(float val) { return val; } + FMT_CONSTEXPR FMT_INLINE double map(double val) { return val; } + FMT_CONSTEXPR FMT_INLINE long double map(long double val) { return val; } + + FMT_CONSTEXPR FMT_INLINE const char_type* map(char_type* val) { return val; } + FMT_CONSTEXPR FMT_INLINE const char_type* map(const char_type* val) { + return val; + } + template ::value)> + FMT_CONSTEXPR FMT_INLINE basic_string_view map(const T& val) { + static_assert(std::is_same>::value, + "mixing character types is disallowed"); + return to_string_view(val); + } + template , T>::value && + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE basic_string_view map(const T& val) { + return basic_string_view(val); + } + template < + typename T, + FMT_ENABLE_IF( + std::is_constructible, T>::value && + !std::is_constructible, T>::value && + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE basic_string_view map(const T& val) { + return std_string_view(val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(const signed char* val) { + static_assert(std::is_same::value, "invalid string type"); + return reinterpret_cast(val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(const unsigned char* val) { + static_assert(std::is_same::value, "invalid string type"); + return reinterpret_cast(val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(signed char* val) { + const auto* const_val = val; + return map(const_val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(unsigned char* val) { + const auto* const_val = val; + return map(const_val); + } + + FMT_CONSTEXPR FMT_INLINE const void* map(void* val) { return val; } + FMT_CONSTEXPR FMT_INLINE const void* map(const void* val) { return val; } + FMT_CONSTEXPR FMT_INLINE const void* map(std::nullptr_t val) { return val; } + + // We use SFINAE instead of a const T* parameter to avoid conflicting with + // the C array overload. + template + FMT_CONSTEXPR auto map(T) -> enable_if_t::value, int> { + // Formatting of arbitrary pointers is disallowed. If you want to output + // a pointer cast it to "void *" or "const void *". In particular, this + // forbids formatting of "[const] volatile char *" which is printed as bool + // by iostreams. + static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); + return 0; + } + + template + FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { + return values; + } + + template ::value && + !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> decltype(std::declval().map( + static_cast::type>(val))) { + return map(static_cast::type>(val)); + } + template ::value && !is_char::value && + (has_formatter::value || + has_fallback_formatter::value))> + FMT_CONSTEXPR FMT_INLINE const T& map(const T& val) { + return val; + } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) + -> decltype(std::declval().map(named_arg.value)) { + return map(named_arg.value); + } + + unformattable map(...) { return {}; } + }; + +// A type constant after applying arg_mapper. + template + using mapped_type_constant = + type_constant().map(std::declval())), + typename Context::char_type>; + + enum { packed_arg_bits = 4 }; +// Maximum number of arguments with packed types. + enum { max_packed_args = 62 / packed_arg_bits }; + enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; + enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; + + FMT_END_DETAIL_NAMESPACE + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in basic_memory_buffer. + template class basic_format_arg { + private: + detail::value value_; + detail::type type_; + + template + friend FMT_CONSTEXPR basic_format_arg detail::make_arg( + const T& value); + + template + friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, + const basic_format_arg& arg) + -> decltype(vis(0)); + + friend class basic_format_args; + friend class dynamic_format_arg_store; + + using char_type = typename Context::char_type; + + template + friend struct detail::arg_data; + + basic_format_arg(const detail::named_arg_info* args, size_t size) + : value_(args, size) {} + + public: + class handle { + public: + explicit handle(detail::custom_value custom) : custom_(custom) {} + + void format(typename Context::parse_context_type& parse_ctx, + Context& ctx) const { + custom_.format(custom_.value, parse_ctx, ctx); + } + + private: + detail::custom_value custom_; + }; + + constexpr basic_format_arg() : type_(detail::type::none_type) {} + + constexpr explicit operator bool() const FMT_NOEXCEPT { + return type_ != detail::type::none_type; + } + + detail::type type() const { return type_; } + + bool is_integral() const { return detail::is_integral_type(type_); } + bool is_arithmetic() const { return detail::is_arithmetic_type(type_); } + }; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ + template + FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( + Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { + using char_type = typename Context::char_type; + switch (arg.type_) { + case detail::type::none_type: + break; + case detail::type::int_type: + return vis(arg.value_.int_value); + case detail::type::uint_type: + return vis(arg.value_.uint_value); + case detail::type::long_long_type: + return vis(arg.value_.long_long_value); + case detail::type::ulong_long_type: + return vis(arg.value_.ulong_long_value); +#if FMT_USE_INT128 + case detail::type::int128_type: + return vis(arg.value_.int128_value); + case detail::type::uint128_type: + return vis(arg.value_.uint128_value); +#else + case detail::type::int128_type: + case detail::type::uint128_type: + break; +#endif + case detail::type::bool_type: + return vis(arg.value_.bool_value); + case detail::type::char_type: + return vis(arg.value_.char_value); + case detail::type::float_type: + return vis(arg.value_.float_value); + case detail::type::double_type: + return vis(arg.value_.double_value); + case detail::type::long_double_type: + return vis(arg.value_.long_double_value); + case detail::type::cstring_type: + return vis(arg.value_.string.data); + case detail::type::string_type: + return vis(basic_string_view(arg.value_.string.data, + arg.value_.string.size)); + case detail::type::pointer_type: + return vis(arg.value_.pointer); + case detail::type::custom_type: + return vis(typename basic_format_arg::handle(arg.value_.custom)); + } + return vis(monostate()); + } + + FMT_BEGIN_DETAIL_NAMESPACE + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 + // A workaround for gcc 4.8 to make void_t work in a SFINAE context. +template struct void_t_impl { using type = void; }; +template +using void_t = typename detail::void_t_impl::type; +#else + template using void_t = void; +#endif + + template + struct is_output_iterator : std::false_type {}; + + template + struct is_output_iterator< + It, T, + void_t::iterator_category, + decltype(*std::declval() = std::declval())>> + : std::true_type {}; + + template + struct is_back_insert_iterator : std::false_type {}; + template + struct is_back_insert_iterator> + : std::true_type {}; + + template + struct is_contiguous_back_insert_iterator : std::false_type {}; + template + struct is_contiguous_back_insert_iterator> + : is_contiguous {}; + template + struct is_contiguous_back_insert_iterator> + : std::true_type {}; + +// A type-erased reference to an std::locale to avoid heavy include. + class locale_ref { + private: + const void* locale_; // A type-erased pointer to std::locale. + + public: + constexpr locale_ref() : locale_(nullptr) {} + template explicit locale_ref(const Locale& loc); + + explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } + + template Locale get() const; + }; + + template constexpr unsigned long long encode_types() { return 0; } + + template + constexpr unsigned long long encode_types() { + return static_cast(mapped_type_constant::value) | + (encode_types() << packed_arg_bits); + } + + template + FMT_CONSTEXPR basic_format_arg make_arg(const T& value) { + basic_format_arg arg; + arg.type_ = mapped_type_constant::value; + arg.value_ = arg_mapper().map(value); + return arg; + } + +// The type template parameter is there to avoid an ODR violation when using +// a fallback formatter in one translation unit and an implicit conversion in +// another (not recommended). + template + FMT_CONSTEXPR FMT_INLINE value make_arg(const T& val) { + const auto& arg = arg_mapper().map(val); + static_assert( + !std::is_same::value, + "Cannot format an argument. To make type T formattable provide a " + "formatter specialization: https://fmt.dev/latest/api.html#udt"); + return arg; + } + + template + inline basic_format_arg make_arg(const T& value) { + return make_arg(value); + } + + FMT_END_DETAIL_NAMESPACE + +// Formatting context. + template class basic_format_context { + public: + /** The character type for the output. */ + using char_type = Char; + + private: + OutputIt out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + using iterator = OutputIt; + using format_arg = basic_format_arg; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + basic_format_context(basic_format_context&&) = default; + basic_format_context(const basic_format_context&) = delete; + void operator=(const basic_format_context&) = delete; + /** + Constructs a ``basic_format_context`` object. References to the arguments are + stored in the object so make sure they have appropriate lifetimes. + */ + constexpr basic_format_context( + OutputIt out, basic_format_args ctx_args, + detail::locale_ref loc = detail::locale_ref()) + : out_(out), args_(ctx_args), loc_(loc) {} + + constexpr format_arg arg(int id) const { return args_.get(id); } + FMT_CONSTEXPR format_arg arg(basic_string_view name) { + return args_.get(name); + } + int arg_id(basic_string_view name) { return args_.get_id(name); } + const basic_format_args& args() const { return args_; } + + FMT_CONSTEXPR detail::error_handler error_handler() { return {}; } + void on_error(const char* message) { error_handler().on_error(message); } + + // Returns an iterator to the beginning of the output range. + FMT_CONSTEXPR iterator out() { return out_; } + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { + if (!detail::is_back_insert_iterator()) out_ = it; + } + + FMT_CONSTEXPR detail::locale_ref locale() { return loc_; } + }; + + template + using buffer_context = + basic_format_context, Char>; + using format_context = buffer_context; + using wformat_context = buffer_context; + +// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164. +#define FMT_BUFFER_CONTEXT(Char) \ + basic_format_context, Char> + + template + using is_formattable = bool_constant< + !std::is_same>().map( + std::declval())), + detail::unformattable>::value && + !detail::has_fallback_formatter::value>; + +/** + \rst + An array of references to arguments. It can be implicitly converted into + `~fmt::basic_format_args` for passing into type-erased formatting functions + such as `~fmt::vformat`. + \endrst + */ + template + class format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif + { + private: + static const size_t num_args = sizeof...(Args); + static const size_t num_named_args = detail::count_named_args(); + static const bool is_packed = num_args <= detail::max_packed_args; + + using value_type = conditional_t, + basic_format_arg>; + + detail::arg_data + data_; + + friend class basic_format_args; + + static constexpr unsigned long long desc = + (is_packed ? detail::encode_types() + : detail::is_unpacked_bit | num_args) | + (num_named_args != 0 + ? static_cast(detail::has_named_args_bit) + : 0); + + public: + FMT_CONSTEXPR FMT_INLINE format_arg_store(const Args&... args) + : +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + basic_format_args(*this), +#endif + data_{detail::make_arg< + is_packed, Context, + detail::mapped_type_constant::value>(args)...} { + detail::init_named_args(data_.named_args(), 0, 0, args...); + } + }; + +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::format_args`. `Context` + can be omitted in which case it defaults to `~fmt::context`. + See `~fmt::arg` for lifetime considerations. + \endrst + */ + template + constexpr format_arg_store make_format_args( + const Args&... args) { + return {args...}; + } + +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references + to arguments and can be implicitly converted to `~fmt::format_args`. + If ``format_str`` is a compile-time string then `make_args_checked` checks + its validity at compile time. + \endrst + */ + template > + FMT_INLINE auto make_args_checked(const S& format_str, + const remove_reference_t&... args) + -> format_arg_store, remove_reference_t...> { + static_assert( + detail::count<( + std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); + detail::check_format_string(format_str); + return {args...}; + } + +/** + \rst + Returns a named argument to be used in a formatting function. + It should only be used in a call to a formatting function or + `dynamic_format_arg_store::push_back`. + + **Example**:: + + fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); + \endrst + */ + template + inline detail::named_arg arg(const Char* name, const T& arg) { + static_assert(!detail::is_named_arg(), "nested named arguments"); + return {name, arg}; + } + +/** + \rst + A view of a collection of formatting arguments. To avoid lifetime issues it + should only be used as a parameter type in type-erased functions such as + ``vformat``:: + + void vlog(string_view format_str, format_args args); // OK + format_args args = make_format_args(42); // Error: dangling reference + \endrst + */ + template class basic_format_args { + public: + using size_type = int; + using format_arg = basic_format_arg; + + private: + // A descriptor that contains information about formatting arguments. + // If the number of arguments is less or equal to max_packed_args then + // argument types are passed in the descriptor. This reduces binary code size + // per formatting function call. + unsigned long long desc_; + union { + // If is_packed() returns true then argument values are stored in values_; + // otherwise they are stored in args_. This is done to improve cache + // locality and reduce compiled code size since storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const detail::value* values_; + const format_arg* args_; + }; + + constexpr bool is_packed() const { + return (desc_ & detail::is_unpacked_bit) == 0; + } + bool has_named_args() const { + return (desc_ & detail::has_named_args_bit) != 0; + } + + FMT_CONSTEXPR detail::type type(int index) const { + int shift = index * detail::packed_arg_bits; + unsigned int mask = (1 << detail::packed_arg_bits) - 1; + return static_cast((desc_ >> shift) & mask); + } + + constexpr FMT_INLINE basic_format_args(unsigned long long desc, + const detail::value* values) + : desc_(desc), values_(values) {} + constexpr basic_format_args(unsigned long long desc, const format_arg* args) + : desc_(desc), args_(args) {} + + public: + constexpr basic_format_args() : desc_(0), args_(nullptr) {} + + /** + \rst + Constructs a `basic_format_args` object from `~fmt::format_arg_store`. + \endrst + */ + template + constexpr FMT_INLINE basic_format_args( + const format_arg_store& store) + : basic_format_args(format_arg_store::desc, + store.data_.args()) {} + + /** + \rst + Constructs a `basic_format_args` object from + `~fmt::dynamic_format_arg_store`. + \endrst + */ + constexpr FMT_INLINE basic_format_args( + const dynamic_format_arg_store& store) + : basic_format_args(store.get_types(), store.data()) {} + + /** + \rst + Constructs a `basic_format_args` object from a dynamic set of arguments. + \endrst + */ + constexpr basic_format_args(const format_arg* args, int count) + : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), + args) {} + + /** Returns the argument with the specified id. */ + FMT_CONSTEXPR format_arg get(int id) const { + format_arg arg; + if (!is_packed()) { + if (id < max_size()) arg = args_[id]; + return arg; + } + if (id >= detail::max_packed_args) return arg; + arg.type_ = type(id); + if (arg.type_ == detail::type::none_type) return arg; + arg.value_ = values_[id]; + return arg; + } + + template format_arg get(basic_string_view name) const { + int id = get_id(name); + return id >= 0 ? get(id) : format_arg(); + } + + template int get_id(basic_string_view name) const { + if (!has_named_args()) return -1; + const auto& named_args = + (is_packed() ? values_[-1] : args_[-1].value_).named_args; + for (size_t i = 0; i < named_args.size; ++i) { + if (named_args.data[i].name == name) return named_args.data[i].id; + } + return -1; + } + + int max_size() const { + unsigned long long max_packed = detail::max_packed_args; + return static_cast(is_packed() ? max_packed + : desc_ & ~detail::is_unpacked_bit); + } + }; + +/** An alias to ``basic_format_args``. */ +// Separate types would result in shorter symbols but break ABI compatibility +// between clang and gcc on ARM (#1919). + using format_args = basic_format_args; + using wformat_args = basic_format_args; + +// We cannot use enum classes as bit fields because of a gcc bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. + namespace align { + enum type { none, left, right, center, numeric }; + } + using align_t = align::type; + namespace sign { + enum type { none, minus, plus, space }; + } + using sign_t = sign::type; + + FMT_BEGIN_DETAIL_NAMESPACE + + void throw_format_error(const char* message); + +// Workaround an array initialization issue in gcc 4.8. + template struct fill_t { + private: + enum { max_size = 4 }; + Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; + unsigned char size_ = 1; + + public: + FMT_CONSTEXPR void operator=(basic_string_view s) { + auto size = s.size(); + if (size > max_size) return throw_format_error("invalid fill"); + for (size_t i = 0; i < size; ++i) data_[i] = s[i]; + size_ = static_cast(size); + } + + constexpr size_t size() const { return size_; } + constexpr const Char* data() const { return data_; } + + FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; } + FMT_CONSTEXPR const Char& operator[](size_t index) const { + return data_[index]; + } + }; + + FMT_END_DETAIL_NAMESPACE + +// Format specifiers for built-in and string types. + template struct basic_format_specs { + int width; + int precision; + char type; + align_t align : 4; + sign_t sign : 3; + bool alt : 1; // Alternate form ('#'). + bool localized : 1; + detail::fill_t fill; + + constexpr basic_format_specs() + : width(0), + precision(-1), + type(0), + align(align::none), + sign(sign::none), + alt(false), + localized(false) {} + }; + + using format_specs = basic_format_specs; + + FMT_BEGIN_DETAIL_NAMESPACE + + enum class arg_id_kind { none, index, name }; + +// An argument reference. + template struct arg_ref { + FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} + + FMT_CONSTEXPR explicit arg_ref(int index) + : kind(arg_id_kind::index), val(index) {} + FMT_CONSTEXPR explicit arg_ref(basic_string_view name) + : kind(arg_id_kind::name), val(name) {} + + FMT_CONSTEXPR arg_ref& operator=(int idx) { + kind = arg_id_kind::index; + val.index = idx; + return *this; + } + + arg_id_kind kind; + union value { + FMT_CONSTEXPR value(int id = 0) : index{id} {} + FMT_CONSTEXPR value(basic_string_view n) : name(n) {} + + int index; + basic_string_view name; + } val; + }; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow re-using the same parsed specifiers with +// different sets of arguments (precompilation of format strings). + template + struct dynamic_format_specs : basic_format_specs { + arg_ref width_ref; + arg_ref precision_ref; + }; + + struct auto_id {}; + +// A format specifier handler that sets fields in basic_format_specs. + template class specs_setter { + public: + explicit FMT_CONSTEXPR specs_setter(basic_format_specs& specs) + : specs_(specs) {} + + FMT_CONSTEXPR specs_setter(const specs_setter& other) + : specs_(other.specs_) {} + + FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } + FMT_CONSTEXPR void on_fill(basic_string_view fill) { + specs_.fill = fill; + } + FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; } + FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; } + FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; } + FMT_CONSTEXPR void on_hash() { specs_.alt = true; } + FMT_CONSTEXPR void on_localized() { specs_.localized = true; } + + FMT_CONSTEXPR void on_zero() { + specs_.align = align::numeric; + specs_.fill[0] = Char('0'); + } + + FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } + FMT_CONSTEXPR void on_precision(int precision) { + specs_.precision = precision; + } + FMT_CONSTEXPR void end_precision() {} + + FMT_CONSTEXPR void on_type(Char type) { + specs_.type = static_cast(type); + } + + protected: + basic_format_specs& specs_; + }; + +// Format spec handler that saves references to arguments representing dynamic +// width and precision to be resolved at formatting time. + template + class dynamic_specs_handler + : public specs_setter { + public: + using char_type = typename ParseContext::char_type; + + FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs& specs, + ParseContext& ctx) + : specs_setter(specs), specs_(specs), context_(ctx) {} + + FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other) + : specs_setter(other), + specs_(other.specs_), + context_(other.context_) {} + + template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { + specs_.width_ref = make_arg_ref(arg_id); + } + + template FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { + specs_.precision_ref = make_arg_ref(arg_id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + context_.on_error(message); + } + + private: + using arg_ref_type = arg_ref; + + FMT_CONSTEXPR arg_ref_type make_arg_ref(int arg_id) { + context_.check_arg_id(arg_id); + return arg_ref_type(arg_id); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) { + return arg_ref_type(context_.next_arg_id()); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view arg_id) { + context_.check_arg_id(arg_id); + basic_string_view format_str( + context_.begin(), to_unsigned(context_.end() - context_.begin())); + return arg_ref_type(arg_id); + } + + dynamic_format_specs& specs_; + ParseContext& context_; + }; + + template constexpr bool is_ascii_letter(Char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + +// Converts a character to ASCII. Returns a number > 127 on conversion failure. + template ::value)> + constexpr Char to_ascii(Char value) { + return value; + } + template ::value)> + constexpr typename std::underlying_type::type to_ascii(Char value) { + return value; + } + + template + FMT_CONSTEXPR int code_point_length(const Char* begin) { + if (const_check(sizeof(Char) != 1)) return 1; + constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; + int len = lengths[static_cast(*begin) >> 3]; + + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + return len + !len; + } + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. + template + FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end, + ErrorHandler&& eh) { + FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); + unsigned value = 0; + // Convert to unsigned to prevent a warning. + const unsigned max_int = to_unsigned(INT_MAX); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*begin - '0'); + ++begin; + } while (begin != end && '0' <= *begin && *begin <= '9'); + if (value > max_int) eh.on_error("number is too big"); + return static_cast(value); + } + +// Parses fill and alignment. + template + FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end, + Handler&& handler) { + FMT_ASSERT(begin != end, ""); + auto align = align::none; + auto p = begin + code_point_length(begin); + if (p >= end) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': + align = align::left; + break; + case '>': + align = align::right; + break; + case '^': + align = align::center; + break; + default: + break; + } + if (align != align::none) { + if (p != begin) { + auto c = *begin; + if (c == '{') + return handler.on_error("invalid fill character '{'"), begin; + handler.on_fill(basic_string_view(begin, to_unsigned(p - begin))); + begin = p + 1; + } else + ++begin; + handler.on_align(align); + break; + } else if (p == begin) { + break; + } + p = begin; + } + return begin; + } + + template FMT_CONSTEXPR bool is_name_start(Char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; + } + + template + FMT_CONSTEXPR const Char* do_parse_arg_id(const Char* begin, const Char* end, + IDHandler&& handler) { + FMT_ASSERT(begin != end, ""); + Char c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + if (c != '0') + index = parse_nonnegative_int(begin, end, handler); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + handler.on_error("invalid format string"); + else + handler(index); + return begin; + } + if (!is_name_start(c)) { + handler.on_error("invalid format string"); + return begin; + } + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); + handler(basic_string_view(begin, to_unsigned(it - begin))); + return it; + } + + template + FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_arg_id(const Char* begin, + const Char* end, + IDHandler&& handler) { + Char c = *begin; + if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); + handler(); + return begin; + } + +// Adapts SpecHandler to IDHandler API for dynamic width. + template struct width_adapter { + explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {} + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } + FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + handler.on_dynamic_width(id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + handler.on_error(message); + } + + SpecHandler& handler; + }; + + template + FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end, + Handler&& handler) { + FMT_ASSERT(begin != end, ""); + if ('0' <= *begin && *begin <= '9') { + handler.on_width(parse_nonnegative_int(begin, end, handler)); + } else if (*begin == '{') { + ++begin; + if (begin != end) + begin = parse_arg_id(begin, end, width_adapter(handler)); + if (begin == end || *begin != '}') + return handler.on_error("invalid format string"), begin; + ++begin; + } + return begin; + } + +// Adapts SpecHandler to IDHandler API for dynamic precision. + template struct precision_adapter { + explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {} + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } + FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + handler.on_dynamic_precision(id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + handler.on_error(message); + } + + SpecHandler& handler; + }; + + template + FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end, + Handler&& handler) { + ++begin; + auto c = begin != end ? *begin : Char(); + if ('0' <= c && c <= '9') { + handler.on_precision(parse_nonnegative_int(begin, end, handler)); + } else if (c == '{') { + ++begin; + if (begin != end) { + begin = + parse_arg_id(begin, end, precision_adapter(handler)); + } + if (begin == end || *begin++ != '}') + return handler.on_error("invalid format string"), begin; + } else { + return handler.on_error("missing precision specifier"), begin; + } + handler.end_precision(); + return begin; + } + +// Parses standard format specifiers and sends notifications about parsed +// components to handler. + template + FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_format_specs( + const Char* begin, const Char* end, SpecHandler&& handler) { + if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) && + *begin != 'L') { + handler.on_type(*begin++); + return begin; + } + + if (begin == end) return begin; + + begin = parse_align(begin, end, handler); + if (begin == end) return begin; + + // Parse sign. + switch (to_ascii(*begin)) { + case '+': + handler.on_plus(); + ++begin; + break; + case '-': + handler.on_minus(); + ++begin; + break; + case ' ': + handler.on_space(); + ++begin; + break; + default: + break; + } + if (begin == end) return begin; + + if (*begin == '#') { + handler.on_hash(); + if (++begin == end) return begin; + } + + // Parse zero flag. + if (*begin == '0') { + handler.on_zero(); + if (++begin == end) return begin; + } + + begin = parse_width(begin, end, handler); + if (begin == end) return begin; + + // Parse precision. + if (*begin == '.') { + begin = parse_precision(begin, end, handler); + if (begin == end) return begin; + } + + if (*begin == 'L') { + handler.on_localized(); + ++begin; + } + + // Parse type. + if (begin != end && *begin != '}') handler.on_type(*begin++); + return begin; + } + +// Return the result via the out param to workaround gcc bug 77539. + template + FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr& out) { + for (out = first; out != last; ++out) { + if (*out == value) return true; + } + return false; + } + + template <> + inline bool find(const char* first, const char* last, char value, + const char*& out) { + out = static_cast( + std::memchr(first, value, to_unsigned(last - first))); + return out != nullptr; + } + + template struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); } + FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + FMT_CONSTEXPR void on_error(const char* message) { + handler.on_error(message); + } + }; + + template + FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin, + const Char* end, + Handler&& handler) { + ++begin; + if (begin == end) return handler.on_error("invalid format string"), end; + if (*begin == '}') { + handler.on_replacement_field(handler.on_arg_id(), begin); + } else if (*begin == '{') { + handler.on_text(begin, begin + 1); + } else { + auto adapter = id_adapter{handler, 0}; + begin = parse_arg_id(begin, end, adapter); + Char c = begin != end ? *begin : Char(); + if (c == '}') { + handler.on_replacement_field(adapter.arg_id, begin); + } else if (c == ':') { + begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; + } else { + return handler.on_error("missing '}' in format string"), end; + } + } + return begin + 1; + } + + template + FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string( + basic_string_view format_str, Handler&& handler) { + // this is most likely a name-lookup defect in msvc's modules implementation + using detail::find; + + auto begin = format_str.data(); + auto end = begin + format_str.size(); + if (end - begin < 32) { + // Use a simple loop instead of memchr for small strings. + const Char* p = begin; + while (p != end) { + auto c = *p++; + if (c == '{') { + handler.on_text(begin, p - 1); + begin = p = parse_replacement_field(p - 1, end, handler); + } else if (c == '}') { + if (p == end || *p != '}') + return handler.on_error("unmatched '}' in format string"); + handler.on_text(begin, p); + begin = ++p; + } + } + handler.on_text(begin, end); + return; + } + struct writer { + FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) { + if (pbegin == pend) return; + for (;;) { + const Char* p = nullptr; + if (!find(pbegin, pend, '}', p)) + return handler_.on_text(pbegin, pend); + ++p; + if (p == pend || *p != '}') + return handler_.on_error("unmatched '}' in format string"); + handler_.on_text(pbegin, p); + pbegin = p + 1; + } + } + Handler& handler_; + } write{handler}; + while (begin != end) { + // Doing two passes with memchr (one for '{' and another for '}') is up to + // 2.5x faster than the naive one-pass implementation on big format strings. + const Char* p = begin; + if (*begin != '{' && !find(begin + 1, end, '{', p)) + return write(begin, end); + write(begin, p); + begin = parse_replacement_field(p, end, handler); + } + } + + template + FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs( + ParseContext& ctx) { + using char_type = typename ParseContext::char_type; + using context = buffer_context; + using mapped_type = conditional_t< + mapped_type_constant::value != type::custom_type, + decltype(arg_mapper().map(std::declval())), T>; + auto f = conditional_t::value, + formatter, + fallback_formatter>(); + return f.parse(ctx); + } + +// A parse context with extra argument id checks. It is only used at compile +// time because adding checks at runtime would introduce substantial overhead +// and would be redundant since argument ids are checked when arguments are +// retrieved anyway. + template + class compile_parse_context + : public basic_format_parse_context { + private: + int num_args_; + using base = basic_format_parse_context; + + public: + explicit FMT_CONSTEXPR compile_parse_context( + basic_string_view format_str, int num_args = INT_MAX, + ErrorHandler eh = {}) + : base(format_str, eh), num_args_(num_args) {} + + FMT_CONSTEXPR int next_arg_id() { + int id = base::next_arg_id(); + if (id >= num_args_) this->on_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) this->on_error("argument not found"); + } + using base::check_arg_id; + }; + + constexpr int invalid_arg_index = -1; + +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + template +constexpr int get_arg_index_by_name(basic_string_view name) { + if constexpr (detail::is_statically_named_arg()) { + if (name == T::name) return N; + } + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name(name); + return invalid_arg_index; +} +#endif + + template + FMT_CONSTEXPR int get_arg_index_by_name(basic_string_view name) { +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name<0, Args...>(name); +#endif + (void)name; + return invalid_arg_index; + } + + template + class format_string_checker { + public: + explicit FMT_CONSTEXPR format_string_checker( + basic_string_view format_str, ErrorHandler eh) + : context_(format_str, num_args, eh), + parse_funcs_{&parse_format_specs...} {} + + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + + FMT_CONSTEXPR int on_arg_id() { return context_.next_arg_id(); } + FMT_CONSTEXPR int on_arg_id(int id) { return context_.check_arg_id(id), id; } + FMT_CONSTEXPR int on_arg_id(basic_string_view id) { +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + auto index = get_arg_index_by_name(id); + if (index == invalid_arg_index) on_error("named argument is not found"); + return context_.check_arg_id(index), index; +#else + (void)id; + on_error("compile-time checks for named arguments require C++20 support"); + return 0; +#endif + } + + FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} + + FMT_CONSTEXPR const Char* on_format_specs(int id, const Char* begin, + const Char*) { + advance_to(context_, begin); + // id >= 0 check is a workaround for gcc 10 bug (#2065). + return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; + } + + FMT_CONSTEXPR void on_error(const char* message) { + context_.on_error(message); + } + + private: + using parse_context_type = compile_parse_context; + enum { num_args = sizeof...(Args) }; + + // Format specifier parsing function. + using parse_func = const Char* (*)(parse_context_type&); + + parse_context_type context_; + parse_func parse_funcs_[num_args > 0 ? num_args : 1]; + }; + + template ::value), int>> + void check_format_string(S format_str) { + FMT_CONSTEXPR_DECL auto s = to_string_view(format_str); + using checker = format_string_checker...>; + FMT_CONSTEXPR_DECL bool invalid_format = + (parse_format_string(s, checker(s, {})), true); + (void)invalid_format; + } + +// Converts string literals to basic_string_view. + template + FMT_CONSTEXPR basic_string_view compile_string_to_view( + const Char (&s)[N]) { + // Remove trailing null character if needed. Won't be present if this is used + // with raw character array (i.e. not defined as a string). + return {s, + N - ((std::char_traits::to_int_type(s[N - 1]) == 0) ? 1 : 0)}; + } + +// Converts string_view to basic_string_view. + template + FMT_CONSTEXPR basic_string_view compile_string_to_view( + const std_string_view& s) { + return {s.data(), s.size()}; + } + +#define FMT_STRING_IMPL(s, base) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ + using char_type = fmt::remove_cvref_t; \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR \ + operator fmt::basic_string_view() const { \ + return fmt::detail::compile_string_to_view(s); \ + } \ + }; \ + return FMT_COMPILE_STRING(); \ + }() + +/** + \rst + Constructs a compile-time format string from a string literal *s*. + + **Example**:: + + // A compile-time error because 'd' is an invalid specifier for strings. + std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); + \endrst + */ +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string) + + template ::value)> + std::basic_string vformat( + basic_string_view format_str, + basic_format_args>> args); + + FMT_API std::string vformat(string_view format_str, format_args args); + + template + void vformat_to( + buffer& buf, basic_string_view format_str, + basic_format_args)> args, + detail::locale_ref loc = {}); + + template ::value)> + inline void vprint_mojibake(std::FILE*, basic_string_view, const Args&) {} + + FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); +#ifndef _WIN32 + inline void vprint_mojibake(std::FILE*, string_view, format_args) {} +#endif + + FMT_END_DETAIL_NAMESPACE + +/** Formats a string and writes the output to ``out``. */ +// GCC 8 and earlier cannot handle std::back_insert_iterator with +// vformat_to(...) overload, so SFINAE on iterator type instead. + template , + bool enable = detail::is_output_iterator::value> + auto vformat_to(OutputIt out, const S& format_str, + basic_format_args>> args) + -> typename std::enable_if::type { + decltype(detail::get_buffer(out)) buf(detail::get_buffer_init(out)); + detail::vformat_to(buf, to_string_view(format_str), args); + return detail::get_iterator(buf); + } + +/** + \rst + Formats arguments, writes the result to the output iterator ``out`` and returns + the iterator past the end of the output range. + + **Example**:: + + std::vector out; + fmt::format_to(std::back_inserter(out), "{}", 42); + \endrst + */ +// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3. + template >::value> + inline auto format_to(OutputIt out, const S& format_str, Args&&... args) -> + typename std::enable_if::type { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return vformat_to(out, to_string_view(format_str), vargs); + } + + template struct format_to_n_result { + /** Iterator past the end of the output range. */ + OutputIt out; + /** Total (not truncated) output size. */ + size_t size; + }; + + template ::value)> + inline format_to_n_result vformat_to_n( + OutputIt out, size_t n, basic_string_view format_str, + basic_format_args>> args) { + detail::iterator_buffer buf(out, + n); + detail::vformat_to(buf, format_str, args); + return {buf.out(), buf.count()}; + } + +/** + \rst + Formats arguments, writes up to ``n`` characters of the result to the output + iterator ``out`` and returns the total output size and the iterator past the + end of the output range. + \endrst + */ + template >::value> + inline auto format_to_n(OutputIt out, size_t n, const S& format_str, + const Args&... args) -> + typename std::enable_if>::type { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return vformat_to_n(out, n, to_string_view(format_str), vargs); + } + +/** + Returns the number of characters in the output of + ``format(format_str, args...)``. + */ + template > + inline size_t formatted_size(const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + detail::counting_buffer<> buf; + detail::vformat_to(buf, to_string_view(format_str), vargs); + return buf.count(); + } + + template > + FMT_INLINE std::basic_string vformat( + const S& format_str, + basic_format_args>> args) { + return detail::vformat(to_string_view(format_str), args); + } + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + #include + std::string message = fmt::format("The answer is {}", 42); + \endrst +*/ +// Pass char_t as a default template parameter instead of using +// std::basic_string> to reduce the symbol size. + template , + FMT_ENABLE_IF(!FMT_COMPILE_TIME_CHECKS || + !std::is_same::value)> + FMT_INLINE std::basic_string format(const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return detail::vformat(to_string_view(format_str), vargs); + } + + FMT_API void vprint(string_view, format_args); + FMT_API void vprint(std::FILE*, string_view, format_args); + +/** + \rst + Formats ``args`` according to specifications in ``format_str`` and writes the + output to the file ``f``. Strings are assumed to be Unicode-encoded unless the + ``FMT_UNICODE`` macro is set to 0. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ + template > + inline void print(std::FILE* f, const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return detail::is_unicode() + ? vprint(f, to_string_view(format_str), vargs) + : detail::vprint_mojibake(f, to_string_view(format_str), vargs); + } + +/** + \rst + Formats ``args`` according to specifications in ``format_str`` and writes + the output to ``stdout``. Strings are assumed to be Unicode-encoded unless + the ``FMT_UNICODE`` macro is set to 0. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ + template > + inline void print(const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return detail::is_unicode() + ? vprint(to_string_view(format_str), vargs) + : detail::vprint_mojibake(stdout, to_string_view(format_str), + vargs); + } + + FMT_MODULE_EXPORT_END + FMT_GCC_PRAGMA("GCC pop_options") +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# include "format.h" +#endif +#endif // FMT_CORE_H_ diff --git a/include/Third_Lib/muduo/base/AsyncLogging.cc b/include/Third_Lib/muduo/base/AsyncLogging.cc new file mode 100644 index 0000000..0f82444 --- /dev/null +++ b/include/Third_Lib/muduo/base/AsyncLogging.cc @@ -0,0 +1,136 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/AsyncLogging.h" +#include "muduo/base/LogFile.h" +#include "muduo/base/Timestamp.h" + +#include + +using namespace muduo; + +AsyncLogging::AsyncLogging(const string& basename, + off_t rollSize, + int flushInterval) + : flushInterval_(flushInterval), + running_(false), + basename_(basename), + rollSize_(rollSize), + thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"), + latch_(1), + mutex_(), + cond_(mutex_), + currentBuffer_(new Buffer), + nextBuffer_(new Buffer), + buffers_() +{ + currentBuffer_->bzero(); + nextBuffer_->bzero(); + buffers_.reserve(16); +} + +void AsyncLogging::append(const char* logline, int len) +{ + muduo::MutexLockGuard lock(mutex_); + if (currentBuffer_->avail() > len) + { + currentBuffer_->append(logline, len); + } + else + { + buffers_.push_back(std::move(currentBuffer_)); + + if (nextBuffer_) + { + currentBuffer_ = std::move(nextBuffer_); + } + else + { + currentBuffer_.reset(new Buffer); // Rarely happens + } + currentBuffer_->append(logline, len); + cond_.notify(); + } +} + +void AsyncLogging::threadFunc() +{ + assert(running_ == true); + latch_.countDown(); + LogFile output(basename_, rollSize_, false); + BufferPtr newBuffer1(new Buffer); + BufferPtr newBuffer2(new Buffer); + newBuffer1->bzero(); + newBuffer2->bzero(); + BufferVector buffersToWrite; + buffersToWrite.reserve(16); + while (running_) + { + assert(newBuffer1 && newBuffer1->length() == 0); + assert(newBuffer2 && newBuffer2->length() == 0); + assert(buffersToWrite.empty()); + + { + muduo::MutexLockGuard lock(mutex_); + if (buffers_.empty()) // unusual usage! + { + cond_.waitForSeconds(flushInterval_); + } + buffers_.push_back(std::move(currentBuffer_)); + currentBuffer_ = std::move(newBuffer1); + buffersToWrite.swap(buffers_); + if (!nextBuffer_) + { + nextBuffer_ = std::move(newBuffer2); + } + } + + assert(!buffersToWrite.empty()); + + if (buffersToWrite.size() > 25) + { + char buf[256]; + snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n", + Timestamp::now().toFormattedString().c_str(), + buffersToWrite.size()-2); + fputs(buf, stderr); + output.append(buf, static_cast(strlen(buf))); + buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end()); + } + + for (const auto& buffer : buffersToWrite) + { + // FIXME: use unbuffered stdio FILE ? or use ::writev ? + output.append(buffer->data(), buffer->length()); + } + + if (buffersToWrite.size() > 2) + { + // drop non-bzero-ed buffers, avoid trashing + buffersToWrite.resize(2); + } + + if (!newBuffer1) + { + assert(!buffersToWrite.empty()); + newBuffer1 = std::move(buffersToWrite.back()); + buffersToWrite.pop_back(); + newBuffer1->reset(); + } + + if (!newBuffer2) + { + assert(!buffersToWrite.empty()); + newBuffer2 = std::move(buffersToWrite.back()); + buffersToWrite.pop_back(); + newBuffer2->reset(); + } + + buffersToWrite.clear(); + output.flush(); + } + output.flush(); +} + diff --git a/include/Third_Lib/muduo/base/AsyncLogging.h b/include/Third_Lib/muduo/base/AsyncLogging.h new file mode 100644 index 0000000..46e77dd --- /dev/null +++ b/include/Third_Lib/muduo/base/AsyncLogging.h @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_ASYNCLOGGING_H +#define MUDUO_BASE_ASYNCLOGGING_H + +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/BoundedBlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/LogStream.h" + +#include +#include + +namespace muduo +{ + +class AsyncLogging : noncopyable +{ + public: + + AsyncLogging(const string& basename, + off_t rollSize, + int flushInterval = 3); + + ~AsyncLogging() + { + if (running_) + { + stop(); + } + } + + void append(const char* logline, int len); + + void start() + { + running_ = true; + thread_.start(); + latch_.wait(); + } + + void stop() NO_THREAD_SAFETY_ANALYSIS + { + running_ = false; + cond_.notify(); + thread_.join(); + } + + private: + + void threadFunc(); + + typedef muduo::detail::FixedBuffer Buffer; + typedef std::vector> BufferVector; + typedef BufferVector::value_type BufferPtr; + + const int flushInterval_; + std::atomic running_; + const string basename_; + const off_t rollSize_; + muduo::Thread thread_; + muduo::CountDownLatch latch_; + muduo::MutexLock mutex_; + muduo::Condition cond_ GUARDED_BY(mutex_); + BufferPtr currentBuffer_ GUARDED_BY(mutex_); + BufferPtr nextBuffer_ GUARDED_BY(mutex_); + BufferVector buffers_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_ASYNCLOGGING_H diff --git a/include/Third_Lib/muduo/base/Atomic.h b/include/Third_Lib/muduo/base/Atomic.h new file mode 100644 index 0000000..6158fac --- /dev/null +++ b/include/Third_Lib/muduo/base/Atomic.h @@ -0,0 +1,97 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_ATOMIC_H +#define MUDUO_BASE_ATOMIC_H + +#include "muduo/base/noncopyable.h" + +#include + +namespace muduo +{ + +namespace detail +{ +template +class AtomicIntegerT : noncopyable +{ + public: + AtomicIntegerT() + : value_(0) + { + } + + // uncomment if you need copying and assignment + // + // AtomicIntegerT(const AtomicIntegerT& that) + // : value_(that.get()) + // {} + // + // AtomicIntegerT& operator=(const AtomicIntegerT& that) + // { + // getAndSet(that.get()); + // return *this; + // } + + T get() + { + // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST) + return __sync_val_compare_and_swap(&value_, 0, 0); + } + + T getAndAdd(T x) + { + // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST) + return __sync_fetch_and_add(&value_, x); + } + + T addAndGet(T x) + { + return getAndAdd(x) + x; + } + + T incrementAndGet() + { + return addAndGet(1); + } + + T decrementAndGet() + { + return addAndGet(-1); + } + + void add(T x) + { + getAndAdd(x); + } + + void increment() + { + incrementAndGet(); + } + + void decrement() + { + decrementAndGet(); + } + + T getAndSet(T newValue) + { + // in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST) + return __sync_lock_test_and_set(&value_, newValue); + } + + private: + volatile T value_; +}; +} // namespace detail + +typedef detail::AtomicIntegerT AtomicInt32; +typedef detail::AtomicIntegerT AtomicInt64; + +} // namespace muduo + +#endif // MUDUO_BASE_ATOMIC_H diff --git a/include/Third_Lib/muduo/base/BUILD.bazel b/include/Third_Lib/muduo/base/BUILD.bazel new file mode 100644 index 0000000..48b598f --- /dev/null +++ b/include/Third_Lib/muduo/base/BUILD.bazel @@ -0,0 +1,23 @@ +cc_library( + name = "base", + srcs = [ + "AsyncLogging.cc", + "Condition.cc", + "CountDownLatch.cc", + "CurrentThread.cc", + "Date.cc", + "Exception.cc", + "FileUtil.cc", + "LogFile.cc", + "LogStream.cc", + "Logging.cc", + "ProcessInfo.cc", + "Thread.cc", + "ThreadPool.cc", + "TimeZone.cc", + "Timestamp.cc", + ], + hdrs = glob(["*.h"]), + linkopts = ["-pthread"], + visibility = ["//visibility:public"], +) diff --git a/include/Third_Lib/muduo/base/BlockingQueue.h b/include/Third_Lib/muduo/base/BlockingQueue.h new file mode 100644 index 0000000..407c012 --- /dev/null +++ b/include/Third_Lib/muduo/base/BlockingQueue.h @@ -0,0 +1,72 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_BLOCKINGQUEUE_H +#define MUDUO_BASE_BLOCKINGQUEUE_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +#include +#include + +namespace muduo +{ + +template +class BlockingQueue : noncopyable +{ + public: + BlockingQueue() + : mutex_(), + notEmpty_(mutex_), + queue_() + { + } + + void put(const T& x) + { + MutexLockGuard lock(mutex_); + queue_.push_back(x); + notEmpty_.notify(); // wait morphing saves us + // http://www.domaigne.com/blog/computing/condvars-signal-with-mutex-locked-or-not/ + } + + void put(T&& x) + { + MutexLockGuard lock(mutex_); + queue_.push_back(std::move(x)); + notEmpty_.notify(); + } + + T take() + { + MutexLockGuard lock(mutex_); + // always use a while-loop, due to spurious wakeup + while (queue_.empty()) + { + notEmpty_.wait(); + } + assert(!queue_.empty()); + T front(std::move(queue_.front())); + queue_.pop_front(); + return front; + } + + size_t size() const + { + MutexLockGuard lock(mutex_); + return queue_.size(); + } + + private: + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + std::deque queue_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_BLOCKINGQUEUE_H diff --git a/include/Third_Lib/muduo/base/BoundedBlockingQueue.h b/include/Third_Lib/muduo/base/BoundedBlockingQueue.h new file mode 100644 index 0000000..cfb4d3b --- /dev/null +++ b/include/Third_Lib/muduo/base/BoundedBlockingQueue.h @@ -0,0 +1,101 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H +#define MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +#include +#include + +namespace muduo +{ + +template +class BoundedBlockingQueue : noncopyable +{ + public: + explicit BoundedBlockingQueue(int maxSize) + : mutex_(), + notEmpty_(mutex_), + notFull_(mutex_), + queue_(maxSize) + { + } + + void put(const T& x) + { + MutexLockGuard lock(mutex_); + while (queue_.full()) + { + notFull_.wait(); + } + assert(!queue_.full()); + queue_.push_back(x); + notEmpty_.notify(); + } + + void put(T&& x) + { + MutexLockGuard lock(mutex_); + while (queue_.full()) + { + notFull_.wait(); + } + assert(!queue_.full()); + queue_.push_back(std::move(x)); + notEmpty_.notify(); + } + + T take() + { + MutexLockGuard lock(mutex_); + while (queue_.empty()) + { + notEmpty_.wait(); + } + assert(!queue_.empty()); + T front(std::move(queue_.front())); + queue_.pop_front(); + notFull_.notify(); + return front; + } + + bool empty() const + { + MutexLockGuard lock(mutex_); + return queue_.empty(); + } + + bool full() const + { + MutexLockGuard lock(mutex_); + return queue_.full(); + } + + size_t size() const + { + MutexLockGuard lock(mutex_); + return queue_.size(); + } + + size_t capacity() const + { + MutexLockGuard lock(mutex_); + return queue_.capacity(); + } + + private: + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + Condition notFull_ GUARDED_BY(mutex_); + boost::circular_buffer queue_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H diff --git a/include/Third_Lib/muduo/base/CMakeLists.txt b/include/Third_Lib/muduo/base/CMakeLists.txt new file mode 100644 index 0000000..96e2d02 --- /dev/null +++ b/include/Third_Lib/muduo/base/CMakeLists.txt @@ -0,0 +1,34 @@ +set(base_SRCS + AsyncLogging.cc + Condition.cc + CountDownLatch.cc + CurrentThread.cc + Date.cc + Exception.cc + FileUtil.cc + LogFile.cc + Logging.cc + LogStream.cc + ProcessInfo.cc + Timestamp.cc + Thread.cc + ThreadPool.cc + TimeZone.cc + ) + +add_library(muduo_base ${base_SRCS}) +target_link_libraries(muduo_base pthread rt) + +#add_library(muduo_base_cpp11 ${base_SRCS}) +#target_link_libraries(muduo_base_cpp11 pthread rt) +#set_target_properties(muduo_base_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") + +install(TARGETS muduo_base DESTINATION lib) +#install(TARGETS muduo_base_cpp11 DESTINATION lib) + +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION include/muduo/base) + +if(MUDUO_BUILD_EXAMPLES) + add_subdirectory(tests) +endif() diff --git a/include/Third_Lib/muduo/base/Condition.cc b/include/Third_Lib/muduo/base/Condition.cc new file mode 100644 index 0000000..47e9d23 --- /dev/null +++ b/include/Third_Lib/muduo/base/Condition.cc @@ -0,0 +1,26 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Condition.h" + +#include + +// returns true if time out, false otherwise. +bool muduo::Condition::waitForSeconds(double seconds) +{ + struct timespec abstime; + // FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind. + clock_gettime(CLOCK_REALTIME, &abstime); + + const int64_t kNanoSecondsPerSecond = 1000000000; + int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); + + abstime.tv_sec += static_cast((abstime.tv_nsec + nanoseconds) / kNanoSecondsPerSecond); + abstime.tv_nsec = static_cast((abstime.tv_nsec + nanoseconds) % kNanoSecondsPerSecond); + + MutexLock::UnassignGuard ug(mutex_); + return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime); +} + diff --git a/include/Third_Lib/muduo/base/Condition.h b/include/Third_Lib/muduo/base/Condition.h new file mode 100644 index 0000000..0181550 --- /dev/null +++ b/include/Third_Lib/muduo/base/Condition.h @@ -0,0 +1,56 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_CONDITION_H +#define MUDUO_BASE_CONDITION_H + +#include "muduo/base/Mutex.h" + +#include + +namespace muduo +{ + +class Condition : noncopyable +{ + public: + explicit Condition(MutexLock& mutex) + : mutex_(mutex) + { + MCHECK(pthread_cond_init(&pcond_, NULL)); + } + + ~Condition() + { + MCHECK(pthread_cond_destroy(&pcond_)); + } + + void wait() + { + MutexLock::UnassignGuard ug(mutex_); + MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex())); + } + + // returns true if time out, false otherwise. + bool waitForSeconds(double seconds); + + void notify() + { + MCHECK(pthread_cond_signal(&pcond_)); + } + + void notifyAll() + { + MCHECK(pthread_cond_broadcast(&pcond_)); + } + + private: + MutexLock& mutex_; + pthread_cond_t pcond_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_CONDITION_H diff --git a/include/Third_Lib/muduo/base/CountDownLatch.cc b/include/Third_Lib/muduo/base/CountDownLatch.cc new file mode 100644 index 0000000..72d26cc --- /dev/null +++ b/include/Third_Lib/muduo/base/CountDownLatch.cc @@ -0,0 +1,41 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/CountDownLatch.h" + +using namespace muduo; + +CountDownLatch::CountDownLatch(int count) + : mutex_(), + condition_(mutex_), + count_(count) +{ +} + +void CountDownLatch::wait() +{ + MutexLockGuard lock(mutex_); + while (count_ > 0) + { + condition_.wait(); + } +} + +void CountDownLatch::countDown() +{ + MutexLockGuard lock(mutex_); + --count_; + if (count_ == 0) + { + condition_.notifyAll(); + } +} + +int CountDownLatch::getCount() const +{ + MutexLockGuard lock(mutex_); + return count_; +} + diff --git a/include/Third_Lib/muduo/base/CountDownLatch.h b/include/Third_Lib/muduo/base/CountDownLatch.h new file mode 100644 index 0000000..9919aef --- /dev/null +++ b/include/Third_Lib/muduo/base/CountDownLatch.h @@ -0,0 +1,34 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_COUNTDOWNLATCH_H +#define MUDUO_BASE_COUNTDOWNLATCH_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +namespace muduo +{ + +class CountDownLatch : noncopyable +{ + public: + + explicit CountDownLatch(int count); + + void wait(); + + void countDown(); + + int getCount() const; + + private: + mutable MutexLock mutex_; + Condition condition_ GUARDED_BY(mutex_); + int count_ GUARDED_BY(mutex_); +}; + +} // namespace muduo +#endif // MUDUO_BASE_COUNTDOWNLATCH_H diff --git a/include/Third_Lib/muduo/base/CurrentThread.cc b/include/Third_Lib/muduo/base/CurrentThread.cc new file mode 100644 index 0000000..15edff0 --- /dev/null +++ b/include/Third_Lib/muduo/base/CurrentThread.cc @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +namespace muduo +{ +namespace CurrentThread +{ +__thread int t_cachedTid = 0; +__thread char t_tidString[32]; +__thread int t_tidStringLength = 6; +__thread const char* t_threadName = "unknown"; +static_assert(std::is_same::value, "pid_t should be int"); + +string stackTrace(bool demangle) +{ + string stack; + const int max_frames = 200; + void* frame[max_frames]; + int nptrs = ::backtrace(frame, max_frames); + char** strings = ::backtrace_symbols(frame, nptrs); + if (strings) + { + size_t len = 256; + char* demangled = demangle ? static_cast(::malloc(len)) : nullptr; + for (int i = 1; i < nptrs; ++i) // skipping the 0-th, which is this function + { + if (demangle) + { + // https://panthema.net/2008/0901-stacktrace-demangled/ + // bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909] + char* left_par = nullptr; + char* plus = nullptr; + for (char* p = strings[i]; *p; ++p) + { + if (*p == '(') + left_par = p; + else if (*p == '+') + plus = p; + } + + if (left_par && plus) + { + *plus = '\0'; + int status = 0; + char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status); + *plus = '+'; + if (status == 0) + { + demangled = ret; // ret could be realloc() + stack.append(strings[i], left_par+1); + stack.append(demangled); + stack.append(plus); + stack.push_back('\n'); + continue; + } + } + } + // Fallback to mangled names + stack.append(strings[i]); + stack.push_back('\n'); + } + free(demangled); + free(strings); + } + return stack; +} + +} // namespace CurrentThread +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/CurrentThread.h b/include/Third_Lib/muduo/base/CurrentThread.h new file mode 100644 index 0000000..33fd8c0 --- /dev/null +++ b/include/Third_Lib/muduo/base/CurrentThread.h @@ -0,0 +1,54 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_CURRENTTHREAD_H +#define MUDUO_BASE_CURRENTTHREAD_H + +#include "muduo/base/Types.h" + +namespace muduo +{ +namespace CurrentThread +{ + // internal + extern __thread int t_cachedTid; + extern __thread char t_tidString[32]; + extern __thread int t_tidStringLength; + extern __thread const char* t_threadName; + void cacheTid(); + + inline int tid() + { + if (__builtin_expect(t_cachedTid == 0, 0)) + { + cacheTid(); + } + return t_cachedTid; + } + + inline const char* tidString() // for logging + { + return t_tidString; + } + + inline int tidStringLength() // for logging + { + return t_tidStringLength; + } + + inline const char* name() + { + return t_threadName; + } + + bool isMainThread(); + + void sleepUsec(int64_t usec); // for testing + + string stackTrace(bool demangle); +} // namespace CurrentThread +} // namespace muduo + +#endif // MUDUO_BASE_CURRENTTHREAD_H diff --git a/include/Third_Lib/muduo/base/Date.cc b/include/Third_Lib/muduo/base/Date.cc new file mode 100644 index 0000000..86b6071 --- /dev/null +++ b/include/Third_Lib/muduo/base/Date.cc @@ -0,0 +1,76 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Date.h" +#include // snprintf +#include // struct tm + +namespace muduo +{ +namespace detail +{ + +char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; + +// algorithm and explanation see: +// http://www.faqs.org/faqs/calendars/faq/part2/ +// http://blog.csdn.net/Solstice + +int getJulianDayNumber(int year, int month, int day) +{ + (void) require_32_bit_integer_at_least; // no warning please + int a = (14 - month) / 12; + int y = year + 4800 - a; + int m = month + 12 * a - 3; + return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; +} + +struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) +{ + int a = julianDayNumber + 32044; + int b = (4 * a + 3) / 146097; + int c = a - ((b * 146097) / 4); + int d = (4 * c + 3) / 1461; + int e = c - ((1461 * d) / 4); + int m = (5 * e + 2) / 153; + Date::YearMonthDay ymd; + ymd.day = e - ((153 * m + 2) / 5) + 1; + ymd.month = m + 3 - 12 * (m / 10); + ymd.year = b * 100 + d - 4800 + (m / 10); + return ymd; +} +} // namespace detail +const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1); +} // namespace muduo + +using namespace muduo; +using namespace muduo::detail; + +Date::Date(int y, int m, int d) + : julianDayNumber_(getJulianDayNumber(y, m, d)) +{ +} + +Date::Date(const struct tm& t) + : julianDayNumber_(getJulianDayNumber( + t.tm_year+1900, + t.tm_mon+1, + t.tm_mday)) +{ +} + +string Date::toIsoString() const +{ + char buf[32]; + YearMonthDay ymd(yearMonthDay()); + snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); + return buf; +} + +Date::YearMonthDay Date::yearMonthDay() const +{ + return getYearMonthDay(julianDayNumber_); +} + diff --git a/include/Third_Lib/muduo/base/Date.h b/include/Third_Lib/muduo/base/Date.h new file mode 100644 index 0000000..2e27b19 --- /dev/null +++ b/include/Third_Lib/muduo/base/Date.h @@ -0,0 +1,119 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_DATE_H +#define MUDUO_BASE_DATE_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +struct tm; + +namespace muduo +{ + +/// +/// Date in Gregorian calendar. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// +class Date : public muduo::copyable + // public boost::less_than_comparable, + // public boost::equality_comparable +{ + public: + + struct YearMonthDay + { + int year; // [1900..2500] + int month; // [1..12] + int day; // [1..31] + }; + + static const int kDaysPerWeek = 7; + static const int kJulianDayOf1970_01_01; + + /// + /// Constucts an invalid Date. + /// + Date() + : julianDayNumber_(0) + {} + + /// + /// Constucts a yyyy-mm-dd Date. + /// + /// 1 <= month <= 12 + Date(int year, int month, int day); + + /// + /// Constucts a Date from Julian Day Number. + /// + explicit Date(int julianDayNum) + : julianDayNumber_(julianDayNum) + {} + + /// + /// Constucts a Date from struct tm + /// + explicit Date(const struct tm&); + + // default copy/assignment/dtor are Okay + + void swap(Date& that) + { + std::swap(julianDayNumber_, that.julianDayNumber_); + } + + bool valid() const { return julianDayNumber_ > 0; } + + /// + /// Converts to yyyy-mm-dd format. + /// + string toIsoString() const; + + struct YearMonthDay yearMonthDay() const; + + int year() const + { + return yearMonthDay().year; + } + + int month() const + { + return yearMonthDay().month; + } + + int day() const + { + return yearMonthDay().day; + } + + // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ] + int weekDay() const + { + return (julianDayNumber_+1) % kDaysPerWeek; + } + + int julianDayNumber() const { return julianDayNumber_; } + + private: + int julianDayNumber_; +}; + +inline bool operator<(Date x, Date y) +{ + return x.julianDayNumber() < y.julianDayNumber(); +} + +inline bool operator==(Date x, Date y) +{ + return x.julianDayNumber() == y.julianDayNumber(); +} + +} // namespace muduo + +#endif // MUDUO_BASE_DATE_H diff --git a/include/Third_Lib/muduo/base/Exception.cc b/include/Third_Lib/muduo/base/Exception.cc new file mode 100644 index 0000000..6e2afbe --- /dev/null +++ b/include/Third_Lib/muduo/base/Exception.cc @@ -0,0 +1,18 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Exception.h" +#include "muduo/base/CurrentThread.h" + +namespace muduo +{ + +Exception::Exception(string msg) + : message_(std::move(msg)), + stack_(CurrentThread::stackTrace(/*demangle=*/false)) +{ +} + +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/Exception.h b/include/Third_Lib/muduo/base/Exception.h new file mode 100644 index 0000000..2a74622 --- /dev/null +++ b/include/Third_Lib/muduo/base/Exception.h @@ -0,0 +1,40 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_EXCEPTION_H +#define MUDUO_BASE_EXCEPTION_H + +#include "muduo/base/Types.h" +#include + +namespace muduo +{ + +class Exception : public std::exception +{ + public: + Exception(string what); + ~Exception() noexcept override = default; + + // default copy-ctor and operator= are okay. + + const char* what() const noexcept override + { + return message_.c_str(); + } + + const char* stackTrace() const noexcept + { + return stack_.c_str(); + } + + private: + string message_; + string stack_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_EXCEPTION_H diff --git a/include/Third_Lib/muduo/base/FileUtil.cc b/include/Third_Lib/muduo/base/FileUtil.cc new file mode 100644 index 0000000..2a73886 --- /dev/null +++ b/include/Third_Lib/muduo/base/FileUtil.cc @@ -0,0 +1,181 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/FileUtil.h" +#include "muduo/base/Logging.h" + +#include +#include +#include +#include +#include +#include + +using namespace muduo; + +FileUtil::AppendFile::AppendFile(StringArg filename) + : fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC + writtenBytes_(0) +{ + assert(fp_); + ::setbuffer(fp_, buffer_, sizeof buffer_); + // posix_fadvise POSIX_FADV_DONTNEED ? +} + +FileUtil::AppendFile::~AppendFile() +{ + ::fclose(fp_); +} + +void FileUtil::AppendFile::append(const char* logline, const size_t len) +{ + size_t n = write(logline, len); + size_t remain = len - n; + while (remain > 0) + { + size_t x = write(logline + n, remain); + if (x == 0) + { + int err = ferror(fp_); + if (err) + { + fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err)); + } + break; + } + n += x; + remain = len - n; // remain -= x + } + + writtenBytes_ += len; +} + +void FileUtil::AppendFile::flush() +{ + ::fflush(fp_); +} + +size_t FileUtil::AppendFile::write(const char* logline, size_t len) +{ + // #undef fwrite_unlocked + return ::fwrite_unlocked(logline, 1, len, fp_); +} + +FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename) + : fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), + err_(0) +{ + buf_[0] = '\0'; + if (fd_ < 0) + { + err_ = errno; + } +} + +FileUtil::ReadSmallFile::~ReadSmallFile() +{ + if (fd_ >= 0) + { + ::close(fd_); // FIXME: check EINTR + } +} + +// return errno +template +int FileUtil::ReadSmallFile::readToString(int maxSize, + String* content, + int64_t* fileSize, + int64_t* modifyTime, + int64_t* createTime) +{ + static_assert(sizeof(off_t) == 8, "_FILE_OFFSET_BITS = 64"); + assert(content != NULL); + int err = err_; + if (fd_ >= 0) + { + content->clear(); + + if (fileSize) + { + struct stat statbuf; + if (::fstat(fd_, &statbuf) == 0) + { + if (S_ISREG(statbuf.st_mode)) + { + *fileSize = statbuf.st_size; + content->reserve(static_cast(std::min(implicit_cast(maxSize), *fileSize))); + } + else if (S_ISDIR(statbuf.st_mode)) + { + err = EISDIR; + } + if (modifyTime) + { + *modifyTime = statbuf.st_mtime; + } + if (createTime) + { + *createTime = statbuf.st_ctime; + } + } + else + { + err = errno; + } + } + + while (content->size() < implicit_cast(maxSize)) + { + size_t toRead = std::min(implicit_cast(maxSize) - content->size(), sizeof(buf_)); + ssize_t n = ::read(fd_, buf_, toRead); + if (n > 0) + { + content->append(buf_, n); + } + else + { + if (n < 0) + { + err = errno; + } + break; + } + } + } + return err; +} + +int FileUtil::ReadSmallFile::readToBuffer(int* size) +{ + int err = err_; + if (fd_ >= 0) + { + ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0); + if (n >= 0) + { + if (size) + { + *size = static_cast(n); + } + buf_[n] = '\0'; + } + else + { + err = errno; + } + } + return err; +} + +template int FileUtil::readFile(StringArg filename, + int maxSize, + string* content, + int64_t*, int64_t*, int64_t*); + +template int FileUtil::ReadSmallFile::readToString( + int maxSize, + string* content, + int64_t*, int64_t*, int64_t*); + diff --git a/include/Third_Lib/muduo/base/FileUtil.h b/include/Third_Lib/muduo/base/FileUtil.h new file mode 100644 index 0000000..62ddebc --- /dev/null +++ b/include/Third_Lib/muduo/base/FileUtil.h @@ -0,0 +1,89 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_BASE_FILEUTIL_H +#define MUDUO_BASE_FILEUTIL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include // for off_t + +namespace muduo +{ +namespace FileUtil +{ + +// read small file < 64KB +class ReadSmallFile : noncopyable +{ + public: + ReadSmallFile(StringArg filename); + ~ReadSmallFile(); + + // return errno + template + int readToString(int maxSize, + String* content, + int64_t* fileSize, + int64_t* modifyTime, + int64_t* createTime); + + /// Read at maxium kBufferSize into buf_ + // return errno + int readToBuffer(int* size); + + const char* buffer() const { return buf_; } + + static const int kBufferSize = 64*1024; + + private: + int fd_; + int err_; + char buf_[kBufferSize]; +}; + +// read the file content, returns errno if error happens. +template +int readFile(StringArg filename, + int maxSize, + String* content, + int64_t* fileSize = NULL, + int64_t* modifyTime = NULL, + int64_t* createTime = NULL) +{ + ReadSmallFile file(filename); + return file.readToString(maxSize, content, fileSize, modifyTime, createTime); +} + +// not thread safe +class AppendFile : noncopyable +{ + public: + explicit AppendFile(StringArg filename); + + ~AppendFile(); + + void append(const char* logline, size_t len); + + void flush(); + + off_t writtenBytes() const { return writtenBytes_; } + + private: + + size_t write(const char* logline, size_t len); + + FILE* fp_; + char buffer_[64*1024]; + off_t writtenBytes_; +}; + +} // namespace FileUtil +} // namespace muduo + +#endif // MUDUO_BASE_FILEUTIL_H + diff --git a/include/Third_Lib/muduo/base/GzipFile.h b/include/Third_Lib/muduo/base/GzipFile.h new file mode 100644 index 0000000..68a538c --- /dev/null +++ b/include/Third_Lib/muduo/base/GzipFile.h @@ -0,0 +1,89 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#pragma once + +#include "muduo/base/StringPiece.h" +#include "muduo/base/noncopyable.h" +#include + +namespace muduo +{ + +class GzipFile : noncopyable +{ + public: + GzipFile(GzipFile&& rhs) noexcept + : file_(rhs.file_) + { + rhs.file_ = NULL; + } + + ~GzipFile() + { + if (file_) + { + ::gzclose(file_); + } + } + + GzipFile& operator=(GzipFile&& rhs) noexcept + { + swap(rhs); + return *this; + } + + bool valid() const { return file_ != NULL; } + void swap(GzipFile& rhs) { std::swap(file_, rhs.file_); } +#if ZLIB_VERNUM >= 0x1240 + bool setBuffer(int size) { return ::gzbuffer(file_, size) == 0; } +#endif + + // return the number of uncompressed bytes actually read, 0 for eof, -1 for error + int read(void* buf, int len) { return ::gzread(file_, buf, len); } + + // return the number of uncompressed bytes actually written + int write(StringPiece buf) { return ::gzwrite(file_, buf.data(), buf.size()); } + + // number of uncompressed bytes + off_t tell() const { return ::gztell(file_); } + +#if ZLIB_VERNUM >= 0x1240 + // number of compressed bytes + off_t offset() const { return ::gzoffset(file_); } +#endif + + // int flush(int f) { return ::gzflush(file_, f); } + + static GzipFile openForRead(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "rbe")); + } + + static GzipFile openForAppend(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "abe")); + } + + static GzipFile openForWriteExclusive(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "wbxe")); + } + + static GzipFile openForWriteTruncate(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "wbe")); + } + + private: + explicit GzipFile(gzFile file) + : file_(file) + { + } + + gzFile file_; +}; + +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/LogFile.cc b/include/Third_Lib/muduo/base/LogFile.cc new file mode 100644 index 0000000..2a12abe --- /dev/null +++ b/include/Third_Lib/muduo/base/LogFile.cc @@ -0,0 +1,133 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/LogFile.h" + +#include "muduo/base/FileUtil.h" +#include "muduo/base/ProcessInfo.h" + +#include +#include +#include + +using namespace muduo; + +LogFile::LogFile(const string& basename, + off_t rollSize, + bool threadSafe, + int flushInterval, + int checkEveryN) + : basename_(basename), + rollSize_(rollSize), + flushInterval_(flushInterval), + checkEveryN_(checkEveryN), + count_(0), + mutex_(threadSafe ? new MutexLock : NULL), + startOfPeriod_(0), + lastRoll_(0), + lastFlush_(0) +{ + assert(basename.find('/') == string::npos); + rollFile(); +} + +LogFile::~LogFile() = default; + +void LogFile::append(const char* logline, int len) +{ + if (mutex_) + { + MutexLockGuard lock(*mutex_); + append_unlocked(logline, len); + } + else + { + append_unlocked(logline, len); + } +} + +void LogFile::flush() +{ + if (mutex_) + { + MutexLockGuard lock(*mutex_); + file_->flush(); + } + else + { + file_->flush(); + } +} + +void LogFile::append_unlocked(const char* logline, int len) +{ + file_->append(logline, len); + + if (file_->writtenBytes() > rollSize_) + { + rollFile(); + } + else + { + ++count_; + if (count_ >= checkEveryN_) + { + count_ = 0; + time_t now = ::time(NULL); + time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_; + if (thisPeriod_ != startOfPeriod_) + { + rollFile(); + } + else if (now - lastFlush_ > flushInterval_) + { + lastFlush_ = now; + file_->flush(); + } + } + } +} + +bool LogFile::rollFile() +{ + time_t now = 0; + string filename = getLogFileName(basename_, &now); + time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; + + if (now > lastRoll_) + { + lastRoll_ = now; + lastFlush_ = now; + startOfPeriod_ = start; + file_.reset(new FileUtil::AppendFile(filename)); + return true; + } + return false; +} + +string LogFile::getLogFileName(const string& basename, time_t* now) +{ + string filename; + filename.reserve(basename.size() + 64); + filename = basename; + + char timebuf[32]; + struct tm tm; + *now = time(NULL); + gmtime_r(now, &tm); // FIXME: localtime_r ? + strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm); + filename += timebuf; + + filename += ProcessInfo::hostname(); + + char pidbuf[32]; + snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); + filename += pidbuf; + + filename += ".log"; + + return filename; +} + diff --git a/include/Third_Lib/muduo/base/LogFile.h b/include/Third_Lib/muduo/base/LogFile.h new file mode 100644 index 0000000..7abd583 --- /dev/null +++ b/include/Third_Lib/muduo/base/LogFile.h @@ -0,0 +1,58 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGFILE_H +#define MUDUO_BASE_LOGFILE_H + +#include "muduo/base/Mutex.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ + +namespace FileUtil +{ +class AppendFile; +} + +class LogFile : noncopyable +{ + public: + LogFile(const string& basename, + off_t rollSize, + bool threadSafe = true, + int flushInterval = 3, + int checkEveryN = 1024); + ~LogFile(); + + void append(const char* logline, int len); + void flush(); + bool rollFile(); + + private: + void append_unlocked(const char* logline, int len); + + static string getLogFileName(const string& basename, time_t* now); + + const string basename_; + const off_t rollSize_; + const int flushInterval_; + const int checkEveryN_; + + int count_; + + std::unique_ptr mutex_; + time_t startOfPeriod_; + time_t lastRoll_; + time_t lastFlush_; + std::unique_ptr file_; + + const static int kRollPerSeconds_ = 60*60*24; +}; + +} // namespace muduo +#endif // MUDUO_BASE_LOGFILE_H diff --git a/include/Third_Lib/muduo/base/LogStream.cc b/include/Third_Lib/muduo/base/LogStream.cc new file mode 100644 index 0000000..cafd5b8 --- /dev/null +++ b/include/Third_Lib/muduo/base/LogStream.cc @@ -0,0 +1,342 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/LogStream.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include + + +using namespace muduo; +using namespace muduo::detail; + +// TODO: better itoa. +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wtautological-compare" +#else +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +namespace muduo +{ +namespace detail +{ + +const char digits[] = "9876543210123456789"; +const char* zero = digits + 9; +static_assert(sizeof(digits) == 20, "wrong number of digits"); + +const char digitsHex[] = "0123456789ABCDEF"; +static_assert(sizeof digitsHex == 17, "wrong number of digitsHex"); + +// Efficient Integer to String Conversions, by Matthew Wilson. +template +size_t convert(char buf[], T value) +{ + T i = value; + char* p = buf; + + do + { + int lsd = static_cast(i % 10); + i /= 10; + *p++ = zero[lsd]; + } while (i != 0); + + if (value < 0) + { + *p++ = '-'; + } + *p = '\0'; + std::reverse(buf, p); + + return p - buf; +} + +size_t convertHex(char buf[], uintptr_t value) +{ + uintptr_t i = value; + char* p = buf; + + do + { + int lsd = static_cast(i % 16); + i /= 16; + *p++ = digitsHex[lsd]; + } while (i != 0); + + *p = '\0'; + std::reverse(buf, p); + + return p - buf; +} + +template class FixedBuffer; +template class FixedBuffer; + +} // namespace detail + +/* + Format a number with 5 characters, including SI units. + [0, 999] + [1.00k, 999k] + [1.00M, 999M] + [1.00G, 999G] + [1.00T, 999T] + [1.00P, 999P] + [1.00E, inf) +*/ +std::string formatSI(int64_t s) +{ + double n = static_cast(s); + char buf[64]; + if (s < 1000) + snprintf(buf, sizeof(buf), "%" PRId64, s); + else if (s < 9995) + snprintf(buf, sizeof(buf), "%.2fk", n/1e3); + else if (s < 99950) + snprintf(buf, sizeof(buf), "%.1fk", n/1e3); + else if (s < 999500) + snprintf(buf, sizeof(buf), "%.0fk", n/1e3); + else if (s < 9995000) + snprintf(buf, sizeof(buf), "%.2fM", n/1e6); + else if (s < 99950000) + snprintf(buf, sizeof(buf), "%.1fM", n/1e6); + else if (s < 999500000) + snprintf(buf, sizeof(buf), "%.0fM", n/1e6); + else if (s < 9995000000) + snprintf(buf, sizeof(buf), "%.2fG", n/1e9); + else if (s < 99950000000) + snprintf(buf, sizeof(buf), "%.1fG", n/1e9); + else if (s < 999500000000) + snprintf(buf, sizeof(buf), "%.0fG", n/1e9); + else if (s < 9995000000000) + snprintf(buf, sizeof(buf), "%.2fT", n/1e12); + else if (s < 99950000000000) + snprintf(buf, sizeof(buf), "%.1fT", n/1e12); + else if (s < 999500000000000) + snprintf(buf, sizeof(buf), "%.0fT", n/1e12); + else if (s < 9995000000000000) + snprintf(buf, sizeof(buf), "%.2fP", n/1e15); + else if (s < 99950000000000000) + snprintf(buf, sizeof(buf), "%.1fP", n/1e15); + else if (s < 999500000000000000) + snprintf(buf, sizeof(buf), "%.0fP", n/1e15); + else + snprintf(buf, sizeof(buf), "%.2fE", n/1e18); + return buf; +} + +/* + [0, 1023] + [1.00Ki, 9.99Ki] + [10.0Ki, 99.9Ki] + [ 100Ki, 1023Ki] + [1.00Mi, 9.99Mi] +*/ +std::string formatIEC(int64_t s) +{ + double n = static_cast(s); + char buf[64]; + const double Ki = 1024.0; + const double Mi = Ki * 1024.0; + const double Gi = Mi * 1024.0; + const double Ti = Gi * 1024.0; + const double Pi = Ti * 1024.0; + const double Ei = Pi * 1024.0; + + if (n < Ki) + snprintf(buf, sizeof buf, "%" PRId64, s); + else if (n < Ki*9.995) + snprintf(buf, sizeof buf, "%.2fKi", n / Ki); + else if (n < Ki*99.95) + snprintf(buf, sizeof buf, "%.1fKi", n / Ki); + else if (n < Ki*1023.5) + snprintf(buf, sizeof buf, "%.0fKi", n / Ki); + + else if (n < Mi*9.995) + snprintf(buf, sizeof buf, "%.2fMi", n / Mi); + else if (n < Mi*99.95) + snprintf(buf, sizeof buf, "%.1fMi", n / Mi); + else if (n < Mi*1023.5) + snprintf(buf, sizeof buf, "%.0fMi", n / Mi); + + else if (n < Gi*9.995) + snprintf(buf, sizeof buf, "%.2fGi", n / Gi); + else if (n < Gi*99.95) + snprintf(buf, sizeof buf, "%.1fGi", n / Gi); + else if (n < Gi*1023.5) + snprintf(buf, sizeof buf, "%.0fGi", n / Gi); + + else if (n < Ti*9.995) + snprintf(buf, sizeof buf, "%.2fTi", n / Ti); + else if (n < Ti*99.95) + snprintf(buf, sizeof buf, "%.1fTi", n / Ti); + else if (n < Ti*1023.5) + snprintf(buf, sizeof buf, "%.0fTi", n / Ti); + + else if (n < Pi*9.995) + snprintf(buf, sizeof buf, "%.2fPi", n / Pi); + else if (n < Pi*99.95) + snprintf(buf, sizeof buf, "%.1fPi", n / Pi); + else if (n < Pi*1023.5) + snprintf(buf, sizeof buf, "%.0fPi", n / Pi); + + else if (n < Ei*9.995) + snprintf(buf, sizeof buf, "%.2fEi", n / Ei ); + else + snprintf(buf, sizeof buf, "%.1fEi", n / Ei ); + return buf; +} + +} // namespace muduo + +template +const char* FixedBuffer::debugString() +{ + *cur_ = '\0'; + return data_; +} + +template +void FixedBuffer::cookieStart() +{ +} + +template +void FixedBuffer::cookieEnd() +{ +} + +void LogStream::staticCheck() +{ + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); +} + +template +void LogStream::formatInteger(T v) +{ + if (buffer_.avail() >= kMaxNumericSize) + { + size_t len = convert(buffer_.current(), v); + buffer_.add(len); + } +} + +LogStream& LogStream::operator<<(short v) +{ + *this << static_cast(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned short v) +{ + *this << static_cast(v); + return *this; +} + +LogStream& LogStream::operator<<(int v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned int v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(long long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned long long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(const void* p) +{ + uintptr_t v = reinterpret_cast(p); + if (buffer_.avail() >= kMaxNumericSize) + { + char* buf = buffer_.current(); + buf[0] = '0'; + buf[1] = 'x'; + size_t len = convertHex(buf+2, v); + buffer_.add(len+2); + } + return *this; +} + +// FIXME: replace this with Grisu3 by Florian Loitsch. +LogStream& LogStream::operator<<(double v) +{ + if (buffer_.avail() >= kMaxNumericSize) + { + int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v); + buffer_.add(len); + } + return *this; +} + +template +Fmt::Fmt(const char* fmt, T val) +{ + static_assert(std::is_arithmetic::value == true, "Must be arithmetic type"); + + length_ = snprintf(buf_, sizeof buf_, fmt, val); + assert(static_cast(length_) < sizeof buf_); +} + +// Explicit instantiations + +template Fmt::Fmt(const char* fmt, char); + +template Fmt::Fmt(const char* fmt, short); +template Fmt::Fmt(const char* fmt, unsigned short); +template Fmt::Fmt(const char* fmt, int); +template Fmt::Fmt(const char* fmt, unsigned int); +template Fmt::Fmt(const char* fmt, long); +template Fmt::Fmt(const char* fmt, unsigned long); +template Fmt::Fmt(const char* fmt, long long); +template Fmt::Fmt(const char* fmt, unsigned long long); + +template Fmt::Fmt(const char* fmt, float); +template Fmt::Fmt(const char* fmt, double); diff --git a/include/Third_Lib/muduo/base/LogStream.h b/include/Third_Lib/muduo/base/LogStream.h new file mode 100644 index 0000000..a28eb46 --- /dev/null +++ b/include/Third_Lib/muduo/base/LogStream.h @@ -0,0 +1,203 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGSTREAM_H +#define MUDUO_BASE_LOGSTREAM_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include +#include // memcpy + +namespace muduo +{ + +namespace detail +{ + +const int kSmallBuffer = 4000; +const int kLargeBuffer = 4000*1000; + +template +class FixedBuffer : noncopyable +{ + public: + FixedBuffer() + : cur_(data_) + { + setCookie(cookieStart); + } + + ~FixedBuffer() + { + setCookie(cookieEnd); + } + + void append(const char* /*restrict*/ buf, size_t len) + { + // FIXME: append partially + if (implicit_cast(avail()) > len) + { + memcpy(cur_, buf, len); + cur_ += len; + } + } + + const char* data() const { return data_; } + int length() const { return static_cast(cur_ - data_); } + + // write to data_ directly + char* current() { return cur_; } + int avail() const { return static_cast(end() - cur_); } + void add(size_t len) { cur_ += len; } + + void reset() { cur_ = data_; } + void bzero() { memZero(data_, sizeof data_); } + + // for used by GDB + const char* debugString(); + void setCookie(void (*cookie)()) { cookie_ = cookie; } + // for used by unit test + string toString() const { return string(data_, length()); } + StringPiece toStringPiece() const { return StringPiece(data_, length()); } + + private: + const char* end() const { return data_ + sizeof data_; } + // Must be outline function for cookies. + static void cookieStart(); + static void cookieEnd(); + + void (*cookie_)(); + char data_[SIZE]; + char* cur_; +}; + +} // namespace detail + +class LogStream : noncopyable +{ + typedef LogStream self; + public: + typedef detail::FixedBuffer Buffer; + + self& operator<<(bool v) + { + buffer_.append(v ? "1" : "0", 1); + return *this; + } + + self& operator<<(short); + self& operator<<(unsigned short); + self& operator<<(int); + self& operator<<(unsigned int); + self& operator<<(long); + self& operator<<(unsigned long); + self& operator<<(long long); + self& operator<<(unsigned long long); + + self& operator<<(const void*); + + self& operator<<(float v) + { + *this << static_cast(v); + return *this; + } + self& operator<<(double); + // self& operator<<(long double); + + self& operator<<(char v) + { + buffer_.append(&v, 1); + return *this; + } + + // self& operator<<(signed char); + // self& operator<<(unsigned char); + + self& operator<<(const char* str) + { + if (str) + { + buffer_.append(str, strlen(str)); + } + else + { + buffer_.append("(null)", 6); + } + return *this; + } + + self& operator<<(const unsigned char* str) + { + return operator<<(reinterpret_cast(str)); + } + + self& operator<<(const string& v) + { + buffer_.append(v.c_str(), v.size()); + return *this; + } + + self& operator<<(const StringPiece& v) + { + buffer_.append(v.data(), v.size()); + return *this; + } + + self& operator<<(const Buffer& v) + { + *this << v.toStringPiece(); + return *this; + } + + void append(const char* data, int len) { buffer_.append(data, len); } + const Buffer& buffer() const { return buffer_; } + void resetBuffer() { buffer_.reset(); } + + private: + void staticCheck(); + + template + void formatInteger(T); + + Buffer buffer_; + + static const int kMaxNumericSize = 32; +}; + +class Fmt // : noncopyable +{ + public: + template + Fmt(const char* fmt, T val); + + const char* data() const { return buf_; } + int length() const { return length_; } + + private: + char buf_[32]; + int length_; +}; + +inline LogStream& operator<<(LogStream& s, const Fmt& fmt) +{ + s.append(fmt.data(), fmt.length()); + return s; +} + +// Format quantity n in SI units (k, M, G, T, P, E). +// The returned string is atmost 5 characters long. +// Requires n >= 0 +string formatSI(int64_t n); + +// Format quantity n in IEC (binary) units (Ki, Mi, Gi, Ti, Pi, Ei). +// The returned string is atmost 6 characters long. +// Requires n >= 0 +string formatIEC(int64_t n); + +} // namespace muduo + +#endif // MUDUO_BASE_LOGSTREAM_H diff --git a/include/Third_Lib/muduo/base/Logging.cc b/include/Third_Lib/muduo/base/Logging.cc new file mode 100644 index 0000000..c09a8ce --- /dev/null +++ b/include/Third_Lib/muduo/base/Logging.cc @@ -0,0 +1,227 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Logging.h" + +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Timestamp.h" +#include "muduo/base/TimeZone.h" + +#include +#include +#include + +#include + +namespace muduo +{ + +/* +class LoggerImpl +{ + public: + typedef Logger::LogLevel LogLevel; + LoggerImpl(LogLevel level, int old_errno, const char* file, int line); + void finish(); + + Timestamp time_; + LogStream stream_; + LogLevel level_; + int line_; + const char* fullname_; + const char* basename_; +}; +*/ + +__thread char t_errnobuf[512]; +__thread char t_time[64]; +__thread time_t t_lastSecond; + +const char* strerror_tl(int savedErrno) +{ + return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); +} + +Logger::LogLevel initLogLevel() +{ + if (::getenv("MUDUO_LOG_TRACE")) + return Logger::TRACE; + else if (::getenv("MUDUO_LOG_DEBUG")) + return Logger::DEBUG; + else + return Logger::INFO; +} + +Logger::LogLevel g_logLevel = initLogLevel(); + +const char* LogLevelName[Logger::NUM_LOG_LEVELS] = +{ + "TRACE ", + "DEBUG ", + "INFO ", + "WARN ", + "ERROR ", + "FATAL ", +}; + +// helper class for known string length at compile time +class T +{ + public: + T(const char* str, unsigned len) + :str_(str), + len_(len) + { + assert(strlen(str) == len_); + } + + const char* str_; + const unsigned len_; +}; + +inline LogStream& operator<<(LogStream& s, T v) +{ + s.append(v.str_, v.len_); + return s; +} + +inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v) +{ + s.append(v.data_, v.size_); + return s; +} + +void defaultOutput(const char* msg, int len) +{ + size_t n = fwrite(msg, 1, len, stdout); + //FIXME check n + (void)n; +} + +void defaultFlush() +{ + fflush(stdout); +} + +Logger::OutputFunc g_output = defaultOutput; +Logger::FlushFunc g_flush = defaultFlush; +TimeZone g_logTimeZone; + +} // namespace muduo + +using namespace muduo; + +Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line) + : time_(Timestamp::now()), + stream_(), + level_(level), + line_(line), + basename_(file) +{ + formatTime(); + CurrentThread::tid(); + stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength()); + stream_ << T(LogLevelName[level], 6); + if (savedErrno != 0) + { + stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; + } +} + +void Logger::Impl::formatTime() +{ + int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch(); + time_t seconds = static_cast(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond); + int microseconds = static_cast(microSecondsSinceEpoch % Timestamp::kMicroSecondsPerSecond); + if (seconds != t_lastSecond) + { + t_lastSecond = seconds; + struct tm tm_time; + if (g_logTimeZone.valid()) + { + tm_time = g_logTimeZone.toLocalTime(seconds); + } + else + { + ::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime + } + + int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + assert(len == 17); (void)len; + } + + if (g_logTimeZone.valid()) + { + Fmt us(".%06d ", microseconds); + assert(us.length() == 8); + stream_ << T(t_time, 17) << T(us.data(), 8); + } + else + { + Fmt us(".%06dZ ", microseconds); + assert(us.length() == 9); + stream_ << T(t_time, 17) << T(us.data(), 9); + } +} + +void Logger::Impl::finish() +{ + stream_ << " - " << basename_ << ':' << line_ << '\n'; +} + +Logger::Logger(SourceFile file, int line) + : impl_(INFO, 0, file, line) +{ +} + +Logger::Logger(SourceFile file, int line, LogLevel level, const char* func) + : impl_(level, 0, file, line) +{ + impl_.stream_ << func << ' '; +} + +Logger::Logger(SourceFile file, int line, LogLevel level) + : impl_(level, 0, file, line) +{ +} + +Logger::Logger(SourceFile file, int line, bool toAbort) + : impl_(toAbort?FATAL:ERROR, errno, file, line) +{ +} + +Logger::~Logger() +{ + impl_.finish(); + const LogStream::Buffer& buf(stream().buffer()); + g_output(buf.data(), buf.length()); + if (impl_.level_ == FATAL) + { + g_flush(); + abort(); + } +} + +void Logger::setLogLevel(Logger::LogLevel level) +{ + g_logLevel = level; +} + +void Logger::setOutput(OutputFunc out) +{ + g_output = out; +} + +void Logger::setFlush(FlushFunc flush) +{ + g_flush = flush; +} + +void Logger::setTimeZone(const TimeZone& tz) +{ + g_logTimeZone = tz; +} diff --git a/include/Third_Lib/muduo/base/Logging.h b/include/Third_Lib/muduo/base/Logging.h new file mode 100644 index 0000000..be56689 --- /dev/null +++ b/include/Third_Lib/muduo/base/Logging.h @@ -0,0 +1,159 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGGING_H +#define MUDUO_BASE_LOGGING_H + +#include "muduo/base/LogStream.h" +#include "muduo/base/Timestamp.h" + +namespace muduo +{ + +class TimeZone; + +class Logger +{ + public: + enum LogLevel + { + TRACE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL, + NUM_LOG_LEVELS, + }; + + // compile time calculation of basename of source file + class SourceFile + { + public: + template + SourceFile(const char (&arr)[N]) + : data_(arr), + size_(N-1) + { + const char* slash = strrchr(data_, '/'); // builtin function + if (slash) + { + data_ = slash + 1; + size_ -= static_cast(data_ - arr); + } + } + + explicit SourceFile(const char* filename) + : data_(filename) + { + const char* slash = strrchr(filename, '/'); + if (slash) + { + data_ = slash + 1; + } + size_ = static_cast(strlen(data_)); + } + + const char* data_; + int size_; + }; + + Logger(SourceFile file, int line); + Logger(SourceFile file, int line, LogLevel level); + Logger(SourceFile file, int line, LogLevel level, const char* func); + Logger(SourceFile file, int line, bool toAbort); + ~Logger(); + + LogStream& stream() { return impl_.stream_; } + + static LogLevel logLevel(); + static void setLogLevel(LogLevel level); + + typedef void (*OutputFunc)(const char* msg, int len); + typedef void (*FlushFunc)(); + static void setOutput(OutputFunc); + static void setFlush(FlushFunc); + static void setTimeZone(const TimeZone& tz); + + private: + +class Impl +{ + public: + typedef Logger::LogLevel LogLevel; + Impl(LogLevel level, int old_errno, const SourceFile& file, int line); + void formatTime(); + void finish(); + + Timestamp time_; + LogStream stream_; + LogLevel level_; + int line_; + SourceFile basename_; +}; + + Impl impl_; + +}; + +extern Logger::LogLevel g_logLevel; + +inline Logger::LogLevel Logger::logLevel() +{ + return g_logLevel; +} + +// +// CAUTION: do not write: +// +// if (good) +// LOG_INFO << "Good news"; +// else +// LOG_WARN << "Bad news"; +// +// this expends to +// +// if (good) +// if (logging_INFO) +// logInfoStream << "Good news"; +// else +// logWarnStream << "Bad news"; +// +#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \ + muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream() +#define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \ + muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream() +#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \ + muduo::Logger(__FILE__, __LINE__).stream() +#define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream() +#define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream() +#define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream() +#define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream() +#define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream() + +const char* strerror_tl(int savedErrno); + +// Taken from glog/logging.h +// +// Check that the input is non NULL. This very useful in constructor +// initializer lists. + +#define CHECK_NOTNULL(val) \ + ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// A small helper for CHECK_NOTNULL(). +template +T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) +{ + if (ptr == NULL) + { + Logger(file, line, Logger::FATAL).stream() << names; + } + return ptr; +} + +} // namespace muduo + +#endif // MUDUO_BASE_LOGGING_H diff --git a/include/Third_Lib/muduo/base/Mutex.h b/include/Third_Lib/muduo/base/Mutex.h new file mode 100644 index 0000000..20746bd --- /dev/null +++ b/include/Third_Lib/muduo/base/Mutex.h @@ -0,0 +1,233 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_MUTEX_H +#define MUDUO_BASE_MUTEX_H + +#include "muduo/base/CurrentThread.h" +#include "muduo/base/noncopyable.h" +#include +#include + +// Thread safety annotations { +// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +// Enable thread safety attributes only with clang. +// The attributes can be safely erased when compiling with other compilers. +#if defined(__clang__) && (!defined(SWIG)) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define SCOPED_CAPABILITY \ + THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define PT_GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define REQUIRES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define REQUIRES_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define RELEASE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define RELEASE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define EXCLUDES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define ASSERT_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define ASSERT_SHARED_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define RETURN_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +// End of thread safety annotations } + +#ifdef CHECK_PTHREAD_RETURN_VALUE + +#ifdef NDEBUG +__BEGIN_DECLS +extern void __assert_perror_fail (int errnum, + const char *file, + unsigned int line, + const char *function) + noexcept __attribute__ ((__noreturn__)); +__END_DECLS +#endif + +#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ + if (__builtin_expect(errnum != 0, 0)) \ + __assert_perror_fail (errnum, __FILE__, __LINE__, __func__);}) + +#else // CHECK_PTHREAD_RETURN_VALUE + +#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ + assert(errnum == 0); (void) errnum;}) + +#endif // CHECK_PTHREAD_RETURN_VALUE + +namespace muduo +{ + +// Use as data member of a class, eg. +// +// class Foo +// { +// public: +// int size() const; +// +// private: +// mutable MutexLock mutex_; +// std::vector data_ GUARDED_BY(mutex_); +// }; +class CAPABILITY("mutex") MutexLock : noncopyable +{ + public: + MutexLock() + : holder_(0) + { + MCHECK(pthread_mutex_init(&mutex_, NULL)); + } + + ~MutexLock() + { + assert(holder_ == 0); + MCHECK(pthread_mutex_destroy(&mutex_)); + } + + // must be called when locked, i.e. for assertion + bool isLockedByThisThread() const + { + return holder_ == CurrentThread::tid(); + } + + void assertLocked() const ASSERT_CAPABILITY(this) + { + assert(isLockedByThisThread()); + } + + // internal usage + + void lock() ACQUIRE() + { + MCHECK(pthread_mutex_lock(&mutex_)); + assignHolder(); + } + + void unlock() RELEASE() + { + unassignHolder(); + MCHECK(pthread_mutex_unlock(&mutex_)); + } + + pthread_mutex_t* getPthreadMutex() /* non-const */ + { + return &mutex_; + } + + private: + friend class Condition; + + class UnassignGuard : noncopyable + { + public: + explicit UnassignGuard(MutexLock& owner) + : owner_(owner) + { + owner_.unassignHolder(); + } + + ~UnassignGuard() + { + owner_.assignHolder(); + } + + private: + MutexLock& owner_; + }; + + void unassignHolder() + { + holder_ = 0; + } + + void assignHolder() + { + holder_ = CurrentThread::tid(); + } + + pthread_mutex_t mutex_; + pid_t holder_; +}; + +// Use as a stack variable, eg. +// int Foo::size() const +// { +// MutexLockGuard lock(mutex_); +// return data_.size(); +// } +class SCOPED_CAPABILITY MutexLockGuard : noncopyable +{ + public: + explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex) + : mutex_(mutex) + { + mutex_.lock(); + } + + ~MutexLockGuard() RELEASE() + { + mutex_.unlock(); + } + + private: + + MutexLock& mutex_; +}; + +} // namespace muduo + +// Prevent misuse like: +// MutexLockGuard(mutex_); +// A tempory object doesn't hold the lock for long! +#define MutexLockGuard(x) error "Missing guard object name" + +#endif // MUDUO_BASE_MUTEX_H diff --git a/include/Third_Lib/muduo/base/ProcessInfo.cc b/include/Third_Lib/muduo/base/ProcessInfo.cc new file mode 100644 index 0000000..6ab5ad1 --- /dev/null +++ b/include/Third_Lib/muduo/base/ProcessInfo.cc @@ -0,0 +1,246 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/ProcessInfo.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/FileUtil.h" + +#include + +#include +#include +#include +#include // snprintf +#include +#include +#include +#include + +namespace muduo +{ +namespace detail +{ +__thread int t_numOpenedFiles = 0; +int fdDirFilter(const struct dirent* d) +{ + if (::isdigit(d->d_name[0])) + { + ++t_numOpenedFiles; + } + return 0; +} + +__thread std::vector* t_pids = NULL; +int taskDirFilter(const struct dirent* d) +{ + if (::isdigit(d->d_name[0])) + { + t_pids->push_back(atoi(d->d_name)); + } + return 0; +} + +int scanDir(const char *dirpath, int (*filter)(const struct dirent *)) +{ + struct dirent** namelist = NULL; + int result = ::scandir(dirpath, &namelist, filter, alphasort); + assert(namelist == NULL); + return result; +} + +Timestamp g_startTime = Timestamp::now(); +// assume those won't change during the life time of a process. +int g_clockTicks = static_cast(::sysconf(_SC_CLK_TCK)); +int g_pageSize = static_cast(::sysconf(_SC_PAGE_SIZE)); +} // namespace detail +} // namespace muduo + +using namespace muduo; +using namespace muduo::detail; + +pid_t ProcessInfo::pid() +{ + return ::getpid(); +} + +string ProcessInfo::pidString() +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", pid()); + return buf; +} + +uid_t ProcessInfo::uid() +{ + return ::getuid(); +} + +string ProcessInfo::username() +{ + struct passwd pwd; + struct passwd* result = NULL; + char buf[8192]; + const char* name = "unknownuser"; + + getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); + if (result) + { + name = pwd.pw_name; + } + return name; +} + +uid_t ProcessInfo::euid() +{ + return ::geteuid(); +} + +Timestamp ProcessInfo::startTime() +{ + return g_startTime; +} + +int ProcessInfo::clockTicksPerSecond() +{ + return g_clockTicks; +} + +int ProcessInfo::pageSize() +{ + return g_pageSize; +} + +bool ProcessInfo::isDebugBuild() +{ +#ifdef NDEBUG + return false; +#else + return true; +#endif +} + +string ProcessInfo::hostname() +{ + // HOST_NAME_MAX 64 + // _POSIX_HOST_NAME_MAX 255 + char buf[256]; + if (::gethostname(buf, sizeof buf) == 0) + { + buf[sizeof(buf)-1] = '\0'; + return buf; + } + else + { + return "unknownhost"; + } +} + +string ProcessInfo::procname() +{ + return procname(procStat()).as_string(); +} + +StringPiece ProcessInfo::procname(const string& stat) +{ + StringPiece name; + size_t lp = stat.find('('); + size_t rp = stat.rfind(')'); + if (lp != string::npos && rp != string::npos && lp < rp) + { + name.set(stat.data()+lp+1, static_cast(rp-lp-1)); + } + return name; +} + +string ProcessInfo::procStatus() +{ + string result; + FileUtil::readFile("/proc/self/status", 65536, &result); + return result; +} + +string ProcessInfo::procStat() +{ + string result; + FileUtil::readFile("/proc/self/stat", 65536, &result); + return result; +} + +string ProcessInfo::threadStat() +{ + char buf[64]; + snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid()); + string result; + FileUtil::readFile(buf, 65536, &result); + return result; +} + +string ProcessInfo::exePath() +{ + string result; + char buf[1024]; + ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf); + if (n > 0) + { + result.assign(buf, n); + } + return result; +} + +int ProcessInfo::openedFiles() +{ + t_numOpenedFiles = 0; + scanDir("/proc/self/fd", fdDirFilter); + return t_numOpenedFiles; +} + +int ProcessInfo::maxOpenFiles() +{ + struct rlimit rl; + if (::getrlimit(RLIMIT_NOFILE, &rl)) + { + return openedFiles(); + } + else + { + return static_cast(rl.rlim_cur); + } +} + +ProcessInfo::CpuTime ProcessInfo::cpuTime() +{ + ProcessInfo::CpuTime t; + struct tms tms; + if (::times(&tms) >= 0) + { + const double hz = static_cast(clockTicksPerSecond()); + t.userSeconds = static_cast(tms.tms_utime) / hz; + t.systemSeconds = static_cast(tms.tms_stime) / hz; + } + return t; +} + +int ProcessInfo::numThreads() +{ + int result = 0; + string status = procStatus(); + size_t pos = status.find("Threads:"); + if (pos != string::npos) + { + result = ::atoi(status.c_str() + pos + 8); + } + return result; +} + +std::vector ProcessInfo::threads() +{ + std::vector result; + t_pids = &result; + scanDir("/proc/self/task", taskDirFilter); + t_pids = NULL; + std::sort(result.begin(), result.end()); + return result; +} + diff --git a/include/Third_Lib/muduo/base/ProcessInfo.h b/include/Third_Lib/muduo/base/ProcessInfo.h new file mode 100644 index 0000000..eae1498 --- /dev/null +++ b/include/Third_Lib/muduo/base/ProcessInfo.h @@ -0,0 +1,68 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_BASE_PROCESSINFO_H +#define MUDUO_BASE_PROCESSINFO_H + +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include "muduo/base/Timestamp.h" +#include +#include + +namespace muduo +{ + +namespace ProcessInfo +{ + pid_t pid(); + string pidString(); + uid_t uid(); + string username(); + uid_t euid(); + Timestamp startTime(); + int clockTicksPerSecond(); + int pageSize(); + bool isDebugBuild(); // constexpr + + string hostname(); + string procname(); + StringPiece procname(const string& stat); + + /// read /proc/self/status + string procStatus(); + + /// read /proc/self/stat + string procStat(); + + /// read /proc/self/task/tid/stat + string threadStat(); + + /// readlink /proc/self/exe + string exePath(); + + int openedFiles(); + int maxOpenFiles(); + + struct CpuTime + { + double userSeconds; + double systemSeconds; + + CpuTime() : userSeconds(0.0), systemSeconds(0.0) { } + + double total() const { return userSeconds + systemSeconds; } + }; + CpuTime cpuTime(); + + int numThreads(); + std::vector threads(); +} // namespace ProcessInfo + +} // namespace muduo + +#endif // MUDUO_BASE_PROCESSINFO_H diff --git a/include/Third_Lib/muduo/base/Singleton.h b/include/Third_Lib/muduo/base/Singleton.h new file mode 100644 index 0000000..5949436 --- /dev/null +++ b/include/Third_Lib/muduo/base/Singleton.h @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_SINGLETON_H +#define MUDUO_BASE_SINGLETON_H + +#include "muduo/base/noncopyable.h" + +#include +#include +#include // atexit + +namespace muduo +{ + +namespace detail +{ +// This doesn't detect inherited member functions! +// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions +template +struct has_no_destroy +{ + template static char test(decltype(&C::no_destroy)); + template static int32_t test(...); + const static bool value = sizeof(test(0)) == 1; +}; +} // namespace detail + +template +class Singleton : noncopyable +{ + public: + Singleton() = delete; + ~Singleton() = delete; + + static T& instance() + { + pthread_once(&ponce_, &Singleton::init); + assert(value_ != NULL); + return *value_; + } + + private: + static void init() + { + value_ = new T(); + if (!detail::has_no_destroy::value) + { + ::atexit(destroy); + } + } + + static void destroy() + { + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + + delete value_; + value_ = NULL; + } + + private: + static pthread_once_t ponce_; + static T* value_; +}; + +template +pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT; + +template +T* Singleton::value_ = NULL; + +} // namespace muduo + +#endif // MUDUO_BASE_SINGLETON_H diff --git a/include/Third_Lib/muduo/base/StringPiece.h b/include/Third_Lib/muduo/base/StringPiece.h new file mode 100644 index 0000000..a62eda0 --- /dev/null +++ b/include/Third_Lib/muduo/base/StringPiece.h @@ -0,0 +1,189 @@ +// Taken from PCRE pcre_stringpiece.h +// +// Copyright (c) 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Sanjay Ghemawat +// +// A string like object that points into another piece of memory. +// Useful for providing an interface that allows clients to easily +// pass in either a "const char*" or a "string". +// +// Arghh! I wish C++ literals were automatically of type "string". + +#ifndef MUDUO_BASE_STRINGPIECE_H +#define MUDUO_BASE_STRINGPIECE_H + +#include +#include // for ostream forward-declaration + +#include "muduo/base/Types.h" + +namespace muduo +{ + +// For passing C-style string argument to a function. +class StringArg // copyable +{ + public: + StringArg(const char* str) + : str_(str) + { } + + StringArg(const string& str) + : str_(str.c_str()) + { } + + const char* c_str() const { return str_; } + + private: + const char* str_; +}; + +class StringPiece { + private: + const char* ptr_; + int length_; + + public: + // We provide non-explicit singleton constructors so users can pass + // in a "const char*" or a "string" wherever a "StringPiece" is + // expected. + StringPiece() + : ptr_(NULL), length_(0) { } + StringPiece(const char* str) + : ptr_(str), length_(static_cast(strlen(ptr_))) { } + StringPiece(const unsigned char* str) + : ptr_(reinterpret_cast(str)), + length_(static_cast(strlen(ptr_))) { } + StringPiece(const string& str) + : ptr_(str.data()), length_(static_cast(str.size())) { } + StringPiece(const char* offset, int len) + : ptr_(offset), length_(len) { } + + // data() may return a pointer to a buffer with embedded NULs, and the + // returned buffer may or may not be null terminated. Therefore it is + // typically a mistake to pass data() to a routine that expects a NUL + // terminated string. Use "as_string().c_str()" if you really need to do + // this. Or better yet, change your routine so it does not rely on NUL + // termination. + const char* data() const { return ptr_; } + int size() const { return length_; } + bool empty() const { return length_ == 0; } + const char* begin() const { return ptr_; } + const char* end() const { return ptr_ + length_; } + + void clear() { ptr_ = NULL; length_ = 0; } + void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; } + void set(const char* str) { + ptr_ = str; + length_ = static_cast(strlen(str)); + } + void set(const void* buffer, int len) { + ptr_ = reinterpret_cast(buffer); + length_ = len; + } + + char operator[](int i) const { return ptr_[i]; } + + void remove_prefix(int n) { + ptr_ += n; + length_ -= n; + } + + void remove_suffix(int n) { + length_ -= n; + } + + bool operator==(const StringPiece& x) const { + return ((length_ == x.length_) && + (memcmp(ptr_, x.ptr_, length_) == 0)); + } + bool operator!=(const StringPiece& x) const { + return !(*this == x); + } + +#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \ + bool operator cmp (const StringPiece& x) const { \ + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \ + return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \ + } + STRINGPIECE_BINARY_PREDICATE(<, <); + STRINGPIECE_BINARY_PREDICATE(<=, <); + STRINGPIECE_BINARY_PREDICATE(>=, >); + STRINGPIECE_BINARY_PREDICATE(>, >); +#undef STRINGPIECE_BINARY_PREDICATE + + int compare(const StringPiece& x) const { + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); + if (r == 0) { + if (length_ < x.length_) r = -1; + else if (length_ > x.length_) r = +1; + } + return r; + } + + string as_string() const { + return string(data(), size()); + } + + void CopyToString(string* target) const { + target->assign(ptr_, length_); + } + + // Does "this" start with "x" + bool starts_with(const StringPiece& x) const { + return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0)); + } +}; + +} // namespace muduo + +// ------------------------------------------------------------------ +// Functions used to create STL containers that use StringPiece +// Remember that a StringPiece's lifetime had better be less than +// that of the underlying string or char*. If it is not, then you +// cannot safely store a StringPiece into an STL container +// ------------------------------------------------------------------ + +#ifdef HAVE_TYPE_TRAITS +// This makes vector really fast for some STL implementations +template<> struct __type_traits { + typedef __true_type has_trivial_default_constructor; + typedef __true_type has_trivial_copy_constructor; + typedef __true_type has_trivial_assignment_operator; + typedef __true_type has_trivial_destructor; + typedef __true_type is_POD_type; +}; +#endif + +// allow StringPiece to be logged +std::ostream& operator<<(std::ostream& o, const muduo::StringPiece& piece); + +#endif // MUDUO_BASE_STRINGPIECE_H diff --git a/include/Third_Lib/muduo/base/Thread.cc b/include/Third_Lib/muduo/base/Thread.cc new file mode 100644 index 0000000..630a0c9 --- /dev/null +++ b/include/Third_Lib/muduo/base/Thread.cc @@ -0,0 +1,200 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Thread.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Exception.h" +#include "muduo/base/Logging.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace muduo +{ +namespace detail +{ + +pid_t gettid() +{ + return static_cast(::syscall(SYS_gettid)); +} + +void afterFork() +{ + muduo::CurrentThread::t_cachedTid = 0; + muduo::CurrentThread::t_threadName = "main"; + CurrentThread::tid(); + // no need to call pthread_atfork(NULL, NULL, &afterFork); +} + +class ThreadNameInitializer +{ + public: + ThreadNameInitializer() + { + muduo::CurrentThread::t_threadName = "main"; + CurrentThread::tid(); + pthread_atfork(NULL, NULL, &afterFork); + } +}; + +ThreadNameInitializer init; + +struct ThreadData +{ + typedef muduo::Thread::ThreadFunc ThreadFunc; + ThreadFunc func_; + string name_; + pid_t* tid_; + CountDownLatch* latch_; + + ThreadData(ThreadFunc func, + const string& name, + pid_t* tid, + CountDownLatch* latch) + : func_(std::move(func)), + name_(name), + tid_(tid), + latch_(latch) + { } + + void runInThread() + { + *tid_ = muduo::CurrentThread::tid(); + tid_ = NULL; + latch_->countDown(); + latch_ = NULL; + + muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str(); + ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName); + try + { + func_(); + muduo::CurrentThread::t_threadName = "finished"; + } + catch (const Exception& ex) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); + abort(); + } + catch (const std::exception& ex) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + abort(); + } + catch (...) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str()); + throw; // rethrow + } + } +}; + +void* startThread(void* obj) +{ + ThreadData* data = static_cast(obj); + data->runInThread(); + delete data; + return NULL; +} + +} // namespace detail + +void CurrentThread::cacheTid() +{ + if (t_cachedTid == 0) + { + t_cachedTid = detail::gettid(); + t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); + } +} + +bool CurrentThread::isMainThread() +{ + return tid() == ::getpid(); +} + +void CurrentThread::sleepUsec(int64_t usec) +{ + struct timespec ts = { 0, 0 }; + ts.tv_sec = static_cast(usec / Timestamp::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast(usec % Timestamp::kMicroSecondsPerSecond * 1000); + ::nanosleep(&ts, NULL); +} + +AtomicInt32 Thread::numCreated_; + +Thread::Thread(ThreadFunc func, const string& n) + : started_(false), + joined_(false), + pthreadId_(0), + tid_(0), + func_(std::move(func)), + name_(n), + latch_(1) +{ + setDefaultName(); +} + +Thread::~Thread() +{ + if (started_ && !joined_) + { + pthread_detach(pthreadId_); + } +} + +void Thread::setDefaultName() +{ + int num = numCreated_.incrementAndGet(); + if (name_.empty()) + { + char buf[32]; + snprintf(buf, sizeof buf, "Thread%d", num); + name_ = buf; + } +} + +void Thread::start() +{ + assert(!started_); + started_ = true; + // FIXME: move(func_) + detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_); + if (pthread_create(&pthreadId_, NULL, &detail::startThread, data)) + { + started_ = false; + delete data; // or no delete? + LOG_SYSFATAL << "Failed in pthread_create"; + } + else + { + latch_.wait(); + assert(tid_ > 0); + } +} + +int Thread::join() +{ + assert(started_); + assert(!joined_); + joined_ = true; + return pthread_join(pthreadId_, NULL); +} + +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/Thread.h b/include/Third_Lib/muduo/base/Thread.h new file mode 100644 index 0000000..d2305a2 --- /dev/null +++ b/include/Third_Lib/muduo/base/Thread.h @@ -0,0 +1,54 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREAD_H +#define MUDUO_BASE_THREAD_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ + +class Thread : noncopyable +{ + public: + typedef std::function ThreadFunc; + + explicit Thread(ThreadFunc, const string& name = string()); + // FIXME: make it movable in C++11 + ~Thread(); + + void start(); + int join(); // return pthread_join() + + bool started() const { return started_; } + // pthread_t pthreadId() const { return pthreadId_; } + pid_t tid() const { return tid_; } + const string& name() const { return name_; } + + static int numCreated() { return numCreated_.get(); } + + private: + void setDefaultName(); + + bool started_; + bool joined_; + pthread_t pthreadId_; + pid_t tid_; + ThreadFunc func_; + string name_; + CountDownLatch latch_; + + static AtomicInt32 numCreated_; +}; + +} // namespace muduo +#endif // MUDUO_BASE_THREAD_H diff --git a/include/Third_Lib/muduo/base/ThreadLocal.h b/include/Third_Lib/muduo/base/ThreadLocal.h new file mode 100644 index 0000000..b8283bc --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadLocal.h @@ -0,0 +1,59 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCAL_H +#define MUDUO_BASE_THREADLOCAL_H + +#include "muduo/base/Mutex.h" +#include "muduo/base/noncopyable.h" + +#include + +namespace muduo +{ + +template +class ThreadLocal : noncopyable +{ + public: + ThreadLocal() + { + MCHECK(pthread_key_create(&pkey_, &ThreadLocal::destructor)); + } + + ~ThreadLocal() + { + MCHECK(pthread_key_delete(pkey_)); + } + + T& value() + { + T* perThreadValue = static_cast(pthread_getspecific(pkey_)); + if (!perThreadValue) + { + T* newObj = new T(); + MCHECK(pthread_setspecific(pkey_, newObj)); + perThreadValue = newObj; + } + return *perThreadValue; + } + + private: + + static void destructor(void *x) + { + T* obj = static_cast(x); + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + delete obj; + } + + private: + pthread_key_t pkey_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_THREADLOCAL_H diff --git a/include/Third_Lib/muduo/base/ThreadLocalSingleton.h b/include/Third_Lib/muduo/base/ThreadLocalSingleton.h new file mode 100644 index 0000000..5c544df --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadLocalSingleton.h @@ -0,0 +1,82 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCALSINGLETON_H +#define MUDUO_BASE_THREADLOCALSINGLETON_H + +#include "muduo/base/noncopyable.h" + +#include +#include + +namespace muduo +{ + +template +class ThreadLocalSingleton : noncopyable +{ + public: + ThreadLocalSingleton() = delete; + ~ThreadLocalSingleton() = delete; + + static T& instance() + { + if (!t_value_) + { + t_value_ = new T(); + deleter_.set(t_value_); + } + return *t_value_; + } + + static T* pointer() + { + return t_value_; + } + + private: + static void destructor(void* obj) + { + assert(obj == t_value_); + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + delete t_value_; + t_value_ = 0; + } + + class Deleter + { + public: + Deleter() + { + pthread_key_create(&pkey_, &ThreadLocalSingleton::destructor); + } + + ~Deleter() + { + pthread_key_delete(pkey_); + } + + void set(T* newObj) + { + assert(pthread_getspecific(pkey_) == NULL); + pthread_setspecific(pkey_, newObj); + } + + pthread_key_t pkey_; + }; + + static __thread T* t_value_; + static Deleter deleter_; +}; + +template +__thread T* ThreadLocalSingleton::t_value_ = 0; + +template +typename ThreadLocalSingleton::Deleter ThreadLocalSingleton::deleter_; + +} // namespace muduo +#endif // MUDUO_BASE_THREADLOCALSINGLETON_H diff --git a/include/Third_Lib/muduo/base/ThreadPool.cc b/include/Third_Lib/muduo/base/ThreadPool.cc new file mode 100644 index 0000000..6905dd7 --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadPool.cc @@ -0,0 +1,156 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/ThreadPool.h" + +#include "muduo/base/Exception.h" + +#include +#include + +using namespace muduo; + +ThreadPool::ThreadPool(const string& nameArg) + : mutex_(), + notEmpty_(mutex_), + notFull_(mutex_), + name_(nameArg), + maxQueueSize_(0), + running_(false) +{ +} + +ThreadPool::~ThreadPool() +{ + if (running_) + { + stop(); + } +} + +void ThreadPool::start(int numThreads) +{ + assert(threads_.empty()); + running_ = true; + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char id[32]; + snprintf(id, sizeof id, "%d", i+1); + threads_.emplace_back(new muduo::Thread( + std::bind(&ThreadPool::runInThread, this), name_+id)); + threads_[i]->start(); + } + if (numThreads == 0 && threadInitCallback_) + { + threadInitCallback_(); + } +} + +void ThreadPool::stop() +{ + { + MutexLockGuard lock(mutex_); + running_ = false; + notEmpty_.notifyAll(); + notFull_.notifyAll(); + } + for (auto& thr : threads_) + { + thr->join(); + } +} + +size_t ThreadPool::queueSize() const +{ + MutexLockGuard lock(mutex_); + return queue_.size(); +} + +void ThreadPool::run(Task task) +{ + if (threads_.empty()) + { + task(); + } + else + { + MutexLockGuard lock(mutex_); + while (isFull() && running_) + { + notFull_.wait(); + } + if (!running_) return; + assert(!isFull()); + + queue_.push_back(std::move(task)); + notEmpty_.notify(); + } +} + +ThreadPool::Task ThreadPool::take() +{ + MutexLockGuard lock(mutex_); + // always use a while-loop, due to spurious wakeup + while (queue_.empty() && running_) + { + notEmpty_.wait(); + } + Task task; + if (!queue_.empty()) + { + task = queue_.front(); + queue_.pop_front(); + if (maxQueueSize_ > 0) + { + notFull_.notify(); + } + } + return task; +} + +bool ThreadPool::isFull() const +{ + mutex_.assertLocked(); + return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_; +} + +void ThreadPool::runInThread() +{ + try + { + if (threadInitCallback_) + { + threadInitCallback_(); + } + while (running_) + { + Task task(take()); + if (task) + { + task(); + } + } + } + catch (const Exception& ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); + abort(); + } + catch (const std::exception& ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + abort(); + } + catch (...) + { + fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str()); + throw; // rethrow + } +} + diff --git a/include/Third_Lib/muduo/base/ThreadPool.h b/include/Third_Lib/muduo/base/ThreadPool.h new file mode 100644 index 0000000..385c1bb --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadPool.h @@ -0,0 +1,67 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADPOOL_H +#define MUDUO_BASE_THREADPOOL_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Types.h" + +#include +#include + +namespace muduo +{ + +class ThreadPool : noncopyable +{ + public: + typedef std::function Task; + + explicit ThreadPool(const string& nameArg = string("ThreadPool")); + ~ThreadPool(); + + // Must be called before start(). + void setMaxQueueSize(int maxSize) { maxQueueSize_ = maxSize; } + void setThreadInitCallback(const Task& cb) + { threadInitCallback_ = cb; } + + void start(int numThreads); + void stop(); + + const string& name() const + { return name_; } + + size_t queueSize() const; + + // Could block if maxQueueSize > 0 + // Call after stop() will return immediately. + // There is no move-only version of std::function in C++ as of C++14. + // So we don't need to overload a const& and an && versions + // as we do in (Bounded)BlockingQueue. + // https://stackoverflow.com/a/25408989 + void run(Task f); + + private: + bool isFull() const REQUIRES(mutex_); + void runInThread(); + Task take(); + + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + Condition notFull_ GUARDED_BY(mutex_); + string name_; + Task threadInitCallback_; + std::vector> threads_; + std::deque queue_ GUARDED_BY(mutex_); + size_t maxQueueSize_; + bool running_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_THREADPOOL_H diff --git a/include/Third_Lib/muduo/base/TimeZone.cc b/include/Third_Lib/muduo/base/TimeZone.cc new file mode 100644 index 0000000..9544385 --- /dev/null +++ b/include/Third_Lib/muduo/base/TimeZone.cc @@ -0,0 +1,363 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/TimeZone.h" +#include "muduo/base/noncopyable.h" +#include "muduo/base/Date.h" + +#include +#include +#include +#include + +#include +//#define _BSD_SOURCE +#include + +#include +#include + +namespace muduo +{ +namespace detail +{ + +struct Transition +{ + time_t gmttime; + time_t localtime; + int localtimeIdx; + + Transition(time_t t, time_t l, int localIdx) + : gmttime(t), localtime(l), localtimeIdx(localIdx) + { } + +}; + +struct Comp +{ + bool compareGmt; + + Comp(bool gmt) + : compareGmt(gmt) + { + } + + bool operator()(const Transition& lhs, const Transition& rhs) const + { + if (compareGmt) + return lhs.gmttime < rhs.gmttime; + else + return lhs.localtime < rhs.localtime; + } + + bool equal(const Transition& lhs, const Transition& rhs) const + { + if (compareGmt) + return lhs.gmttime == rhs.gmttime; + else + return lhs.localtime == rhs.localtime; + } +}; + +struct Localtime +{ + time_t gmtOffset; + bool isDst; + int arrbIdx; + + Localtime(time_t offset, bool dst, int arrb) + : gmtOffset(offset), isDst(dst), arrbIdx(arrb) + { } +}; + +inline void fillHMS(unsigned seconds, struct tm* utc) +{ + utc->tm_sec = seconds % 60; + unsigned minutes = seconds / 60; + utc->tm_min = minutes % 60; + utc->tm_hour = minutes / 60; +} + +} // namespace detail +const int kSecondsPerDay = 24*60*60; +} // namespace muduo + +using namespace muduo; +using namespace std; + +struct TimeZone::Data +{ + vector transitions; + vector localtimes; + vector names; + string abbreviation; +}; + +namespace muduo +{ +namespace detail +{ + +class File : noncopyable +{ + public: + File(const char* file) + : fp_(::fopen(file, "rb")) + { + } + + ~File() + { + if (fp_) + { + ::fclose(fp_); + } + } + + bool valid() const { return fp_; } + + string readBytes(int n) + { + char buf[n]; + ssize_t nr = ::fread(buf, 1, n, fp_); + if (nr != n) + throw logic_error("no enough data"); + return string(buf, n); + } + + int32_t readInt32() + { + int32_t x = 0; + ssize_t nr = ::fread(&x, 1, sizeof(int32_t), fp_); + if (nr != sizeof(int32_t)) + throw logic_error("bad int32_t data"); + return be32toh(x); + } + + uint8_t readUInt8() + { + uint8_t x = 0; + ssize_t nr = ::fread(&x, 1, sizeof(uint8_t), fp_); + if (nr != sizeof(uint8_t)) + throw logic_error("bad uint8_t data"); + return x; + } + + private: + FILE* fp_; +}; + +bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) +{ + File f(zonefile); + if (f.valid()) + { + try + { + string head = f.readBytes(4); + if (head != "TZif") + throw logic_error("bad head"); + string version = f.readBytes(1); + f.readBytes(15); + + int32_t isgmtcnt = f.readInt32(); + int32_t isstdcnt = f.readInt32(); + int32_t leapcnt = f.readInt32(); + int32_t timecnt = f.readInt32(); + int32_t typecnt = f.readInt32(); + int32_t charcnt = f.readInt32(); + + vector trans; + vector localtimes; + trans.reserve(timecnt); + for (int i = 0; i < timecnt; ++i) + { + trans.push_back(f.readInt32()); + } + + for (int i = 0; i < timecnt; ++i) + { + uint8_t local = f.readUInt8(); + localtimes.push_back(local); + } + + for (int i = 0; i < typecnt; ++i) + { + int32_t gmtoff = f.readInt32(); + uint8_t isdst = f.readUInt8(); + uint8_t abbrind = f.readUInt8(); + + data->localtimes.push_back(Localtime(gmtoff, isdst, abbrind)); + } + + for (int i = 0; i < timecnt; ++i) + { + int localIdx = localtimes[i]; + time_t localtime = trans[i] + data->localtimes[localIdx].gmtOffset; + data->transitions.push_back(Transition(trans[i], localtime, localIdx)); + } + + data->abbreviation = f.readBytes(charcnt); + + // leapcnt + for (int i = 0; i < leapcnt; ++i) + { + // int32_t leaptime = f.readInt32(); + // int32_t cumleap = f.readInt32(); + } + // FIXME + (void) isstdcnt; + (void) isgmtcnt; + } + catch (logic_error& e) + { + fprintf(stderr, "%s\n", e.what()); + } + } + return true; +} + +const Localtime* findLocaltime(const TimeZone::Data& data, Transition sentry, Comp comp) +{ + const Localtime* local = NULL; + + if (data.transitions.empty() || comp(sentry, data.transitions.front())) + { + // FIXME: should be first non dst time zone + local = &data.localtimes.front(); + } + else + { + vector::const_iterator transI = lower_bound(data.transitions.begin(), + data.transitions.end(), + sentry, + comp); + if (transI != data.transitions.end()) + { + if (!comp.equal(sentry, *transI)) + { + assert(transI != data.transitions.begin()); + --transI; + } + local = &data.localtimes[transI->localtimeIdx]; + } + else + { + // FIXME: use TZ-env + local = &data.localtimes[data.transitions.back().localtimeIdx]; + } + } + + return local; +} + +} // namespace detail +} // namespace muduo + + +TimeZone::TimeZone(const char* zonefile) + : data_(new TimeZone::Data) +{ + if (!detail::readTimeZoneFile(zonefile, data_.get())) + { + data_.reset(); + } +} + +TimeZone::TimeZone(int eastOfUtc, const char* name) + : data_(new TimeZone::Data) +{ + data_->localtimes.push_back(detail::Localtime(eastOfUtc, false, 0)); + data_->abbreviation = name; +} + +struct tm TimeZone::toLocalTime(time_t seconds) const +{ + struct tm localTime; + memZero(&localTime, sizeof(localTime)); + assert(data_ != NULL); + const Data& data(*data_); + + detail::Transition sentry(seconds, 0, 0); + const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(true)); + + if (local) + { + time_t localSeconds = seconds + local->gmtOffset; + ::gmtime_r(&localSeconds, &localTime); // FIXME: fromUtcTime + localTime.tm_isdst = local->isDst; + localTime.tm_gmtoff = local->gmtOffset; + localTime.tm_zone = &data.abbreviation[local->arrbIdx]; + } + + return localTime; +} + +time_t TimeZone::fromLocalTime(const struct tm& localTm) const +{ + assert(data_ != NULL); + const Data& data(*data_); + + struct tm tmp = localTm; + time_t seconds = ::timegm(&tmp); // FIXME: toUtcTime + detail::Transition sentry(0, seconds, 0); + const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(false)); + if (localTm.tm_isdst) + { + struct tm tryTm = toLocalTime(seconds - local->gmtOffset); + if (!tryTm.tm_isdst + && tryTm.tm_hour == localTm.tm_hour + && tryTm.tm_min == localTm.tm_min) + { + // FIXME: HACK + seconds -= 3600; + } + } + return seconds - local->gmtOffset; +} + +struct tm TimeZone::toUtcTime(time_t secondsSinceEpoch, bool yday) +{ + struct tm utc; + memZero(&utc, sizeof(utc)); + utc.tm_zone = "GMT"; + int seconds = static_cast(secondsSinceEpoch % kSecondsPerDay); + int days = static_cast(secondsSinceEpoch / kSecondsPerDay); + if (seconds < 0) + { + seconds += kSecondsPerDay; + --days; + } + detail::fillHMS(seconds, &utc); + Date date(days + Date::kJulianDayOf1970_01_01); + Date::YearMonthDay ymd = date.yearMonthDay(); + utc.tm_year = ymd.year - 1900; + utc.tm_mon = ymd.month - 1; + utc.tm_mday = ymd.day; + utc.tm_wday = date.weekDay(); + + if (yday) + { + Date startOfYear(ymd.year, 1, 1); + utc.tm_yday = date.julianDayNumber() - startOfYear.julianDayNumber(); + } + return utc; +} + +time_t TimeZone::fromUtcTime(const struct tm& utc) +{ + return fromUtcTime(utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, + utc.tm_hour, utc.tm_min, utc.tm_sec); +} + +time_t TimeZone::fromUtcTime(int year, int month, int day, + int hour, int minute, int seconds) +{ + Date date(year, month, day); + int secondsInDay = hour * 3600 + minute * 60 + seconds; + time_t days = date.julianDayNumber() - Date::kJulianDayOf1970_01_01; + return days * kSecondsPerDay + secondsInDay; +} diff --git a/include/Third_Lib/muduo/base/TimeZone.h b/include/Third_Lib/muduo/base/TimeZone.h new file mode 100644 index 0000000..6586630 --- /dev/null +++ b/include/Third_Lib/muduo/base/TimeZone.h @@ -0,0 +1,52 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_TIMEZONE_H +#define MUDUO_BASE_TIMEZONE_H + +#include "muduo/base/copyable.h" +#include +#include + +namespace muduo +{ + +// TimeZone for 1970~2030 +class TimeZone : public muduo::copyable +{ + public: + explicit TimeZone(const char* zonefile); + TimeZone(int eastOfUtc, const char* tzname); // a fixed timezone + TimeZone() = default; // an invalid timezone + + // default copy ctor/assignment/dtor are Okay. + + bool valid() const + { + // 'explicit operator bool() const' in C++11 + return static_cast(data_); + } + + struct tm toLocalTime(time_t secondsSinceEpoch) const; + time_t fromLocalTime(const struct tm&) const; + + // gmtime(3) + static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); + // timegm(3) + static time_t fromUtcTime(const struct tm&); + // year in [1900..2500], month in [1..12], day in [1..31] + static time_t fromUtcTime(int year, int month, int day, + int hour, int minute, int seconds); + + struct Data; + + private: + + std::shared_ptr data_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_TIMEZONE_H diff --git a/include/Third_Lib/muduo/base/Timestamp.cc b/include/Third_Lib/muduo/base/Timestamp.cc new file mode 100644 index 0000000..fc0ed70 --- /dev/null +++ b/include/Third_Lib/muduo/base/Timestamp.cc @@ -0,0 +1,62 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Timestamp.h" + +#include +#include + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include + +using namespace muduo; + +static_assert(sizeof(Timestamp) == sizeof(int64_t), + "Timestamp should be same size as int64_t"); + +string Timestamp::toString() const +{ + char buf[32] = {0}; + int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; + int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; + snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, microseconds); + return buf; +} + +string Timestamp::toFormattedString(bool showMicroseconds) const +{ + char buf[64] = {0}; + time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); + struct tm tm_time; + gmtime_r(&seconds, &tm_time); + + if (showMicroseconds) + { + int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond); + snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, + microseconds); + } + else + { + snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + } + return buf; +} + +Timestamp Timestamp::now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t seconds = tv.tv_sec; + return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); +} + diff --git a/include/Third_Lib/muduo/base/Timestamp.h b/include/Third_Lib/muduo/base/Timestamp.h new file mode 100644 index 0000000..ccb522d --- /dev/null +++ b/include/Third_Lib/muduo/base/Timestamp.h @@ -0,0 +1,123 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_TIMESTAMP_H +#define MUDUO_BASE_TIMESTAMP_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ + +/// +/// Time stamp in UTC, in microseconds resolution. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// +class Timestamp : public muduo::copyable, + public boost::equality_comparable, + public boost::less_than_comparable +{ + public: + /// + /// Constucts an invalid Timestamp. + /// + Timestamp() + : microSecondsSinceEpoch_(0) + { + } + + /// + /// Constucts a Timestamp at specific time + /// + /// @param microSecondsSinceEpoch + explicit Timestamp(int64_t microSecondsSinceEpochArg) + : microSecondsSinceEpoch_(microSecondsSinceEpochArg) + { + } + + void swap(Timestamp& that) + { + std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); + } + + // default copy/assignment/dtor are Okay + + string toString() const; + string toFormattedString(bool showMicroseconds = true) const; + + bool valid() const { return microSecondsSinceEpoch_ > 0; } + + // for internal usage. + int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } + time_t secondsSinceEpoch() const + { return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); } + + /// + /// Get time of now. + /// + static Timestamp now(); + static Timestamp invalid() + { + return Timestamp(); + } + + static Timestamp fromUnixTime(time_t t) + { + return fromUnixTime(t, 0); + } + + static Timestamp fromUnixTime(time_t t, int microseconds) + { + return Timestamp(static_cast(t) * kMicroSecondsPerSecond + microseconds); + } + + static const int kMicroSecondsPerSecond = 1000 * 1000; + + private: + int64_t microSecondsSinceEpoch_; +}; + +inline bool operator<(Timestamp lhs, Timestamp rhs) +{ + return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); +} + +inline bool operator==(Timestamp lhs, Timestamp rhs) +{ + return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); +} + +/// +/// Gets time difference of two timestamps, result in seconds. +/// +/// @param high, low +/// @return (high-low) in seconds +/// @c double has 52-bit precision, enough for one-microsecond +/// resolution for next 100 years. +inline double timeDifference(Timestamp high, Timestamp low) +{ + int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); + return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; +} + +/// +/// Add @c seconds to given timestamp. +/// +/// @return timestamp+seconds as Timestamp +/// +inline Timestamp addTime(Timestamp timestamp, double seconds) +{ + int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); + return Timestamp(timestamp.microSecondsSinceEpoch() + delta); +} + +} // namespace muduo + +#endif // MUDUO_BASE_TIMESTAMP_H diff --git a/include/Third_Lib/muduo/base/Types.h b/include/Third_Lib/muduo/base/Types.h new file mode 100644 index 0000000..ad94756 --- /dev/null +++ b/include/Third_Lib/muduo/base/Types.h @@ -0,0 +1,123 @@ +#ifndef MUDUO_BASE_TYPES_H +#define MUDUO_BASE_TYPES_H + +#include +#include // memset +#include + +#ifndef NDEBUG +#include +#endif + +/// +/// The most common stuffs. +/// +namespace muduo +{ + +using std::string; + +inline void memZero(void* p, size_t n) +{ + memset(p, 0, n); +} + +// Taken from google-protobuf stubs/common.h +// +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) and others +// +// Contains basic types and utilities used by the rest of the library. + +// +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) +{ + return f; +} + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. + +template // use like this: down_cast(foo); +inline To down_cast(From* f) // so we only accept pointers +{ + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) + { + implicit_cast(0); + } + +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) + assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif + return static_cast(f); +} + +} // namespace muduo + +#endif // MUDUO_BASE_TYPES_H diff --git a/include/Third_Lib/muduo/base/WeakCallback.h b/include/Third_Lib/muduo/base/WeakCallback.h new file mode 100644 index 0000000..5e4650c --- /dev/null +++ b/include/Third_Lib/muduo/base/WeakCallback.h @@ -0,0 +1,65 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_WEAKCALLBACK_H +#define MUDUO_BASE_WEAKCALLBACK_H + +#include +#include + +namespace muduo +{ + +// A barely usable WeakCallback + +template +class WeakCallback +{ + public: + + WeakCallback(const std::weak_ptr& object, + const std::function& function) + : object_(object), function_(function) + { + } + + // Default dtor, copy ctor and assignment are okay + + void operator()(ARGS&&... args) const + { + std::shared_ptr ptr(object_.lock()); + if (ptr) + { + function_(ptr.get(), std::forward(args)...); + } + // else + // { + // LOG_TRACE << "expired"; + // } + } + + private: + + std::weak_ptr object_; + std::function function_; +}; + +template +WeakCallback makeWeakCallback(const std::shared_ptr& object, + void (CLASS::*function)(ARGS...)) +{ + return WeakCallback(object, function); +} + +template +WeakCallback makeWeakCallback(const std::shared_ptr& object, + void (CLASS::*function)(ARGS...) const) +{ + return WeakCallback(object, function); +} + +} // namespace muduo + +#endif // MUDUO_BASE_WEAKCALLBACK_H diff --git a/include/Third_Lib/muduo/base/copyable.h b/include/Third_Lib/muduo/base/copyable.h new file mode 100644 index 0000000..352b287 --- /dev/null +++ b/include/Third_Lib/muduo/base/copyable.h @@ -0,0 +1,19 @@ +#ifndef MUDUO_BASE_COPYABLE_H +#define MUDUO_BASE_COPYABLE_H + +namespace muduo +{ + +/// A tag class emphasises the objects are copyable. +/// The empty base class optimization applies. +/// Any derived class of copyable should be a value type. +class copyable +{ + protected: + copyable() = default; + ~copyable() = default; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_COPYABLE_H diff --git a/include/Third_Lib/muduo/base/noncopyable.h b/include/Third_Lib/muduo/base/noncopyable.h new file mode 100644 index 0000000..79931f9 --- /dev/null +++ b/include/Third_Lib/muduo/base/noncopyable.h @@ -0,0 +1,20 @@ +#ifndef MUDUO_BASE_NONCOPYABLE_H +#define MUDUO_BASE_NONCOPYABLE_H + +namespace muduo +{ + +class noncopyable +{ + public: + noncopyable(const noncopyable&) = delete; + void operator=(const noncopyable&) = delete; + + protected: + noncopyable() = default; + ~noncopyable() = default; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_NONCOPYABLE_H diff --git a/include/Third_Lib/muduo/base/tests/AsyncLogging_test.cc b/include/Third_Lib/muduo/base/tests/AsyncLogging_test.cc new file mode 100644 index 0000000..ad6fde4 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/AsyncLogging_test.cc @@ -0,0 +1,64 @@ +#include "muduo/base/AsyncLogging.h" +#include "muduo/base/Logging.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include + +off_t kRollSize = 500*1000*1000; + +muduo::AsyncLogging* g_asyncLog = NULL; + +void asyncOutput(const char* msg, int len) +{ + g_asyncLog->append(msg, len); +} + +void bench(bool longLog) +{ + muduo::Logger::setOutput(asyncOutput); + + int cnt = 0; + const int kBatch = 1000; + muduo::string empty = " "; + muduo::string longStr(3000, 'X'); + longStr += " "; + + for (int t = 0; t < 30; ++t) + { + muduo::Timestamp start = muduo::Timestamp::now(); + for (int i = 0; i < kBatch; ++i) + { + LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz " + << (longLog ? longStr : empty) + << cnt; + ++cnt; + } + muduo::Timestamp end = muduo::Timestamp::now(); + printf("%f\n", timeDifference(end, start)*1000000/kBatch); + struct timespec ts = { 0, 500*1000*1000 }; + nanosleep(&ts, NULL); + } +} + +int main(int argc, char* argv[]) +{ + { + // set max virtual memory to 2GB. + size_t kOneGB = 1000*1024*1024; + rlimit rl = { 2*kOneGB, 2*kOneGB }; + setrlimit(RLIMIT_AS, &rl); + } + + printf("pid = %d\n", getpid()); + + char name[256] = { '\0' }; + strncpy(name, argv[0], sizeof name - 1); + muduo::AsyncLogging log(::basename(name), kRollSize); + log.start(); + g_asyncLog = &log; + + bool longLog = argc > 1; + bench(longLog); +} diff --git a/include/Third_Lib/muduo/base/tests/Atomic_unittest.cc b/include/Third_Lib/muduo/base/tests/Atomic_unittest.cc new file mode 100644 index 0000000..11d6107 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Atomic_unittest.cc @@ -0,0 +1,38 @@ +#include "muduo/base/Atomic.h" +#include + +int main() +{ + { + muduo::AtomicInt64 a0; + assert(a0.get() == 0); + assert(a0.getAndAdd(1) == 0); + assert(a0.get() == 1); + assert(a0.addAndGet(2) == 3); + assert(a0.get() == 3); + assert(a0.incrementAndGet() == 4); + assert(a0.get() == 4); + a0.increment(); + assert(a0.get() == 5); + assert(a0.addAndGet(-3) == 2); + assert(a0.getAndSet(100) == 2); + assert(a0.get() == 100); + } + + { + muduo::AtomicInt32 a1; + assert(a1.get() == 0); + assert(a1.getAndAdd(1) == 0); + assert(a1.get() == 1); + assert(a1.addAndGet(2) == 3); + assert(a1.get() == 3); + assert(a1.incrementAndGet() == 4); + assert(a1.get() == 4); + a1.increment(); + assert(a1.get() == 5); + assert(a1.addAndGet(-3) == 2); + assert(a1.getAndSet(100) == 2); + assert(a1.get() == 100); + } +} + diff --git a/include/Third_Lib/muduo/base/tests/BlockingQueue_bench.cc b/include/Third_Lib/muduo/base/tests/BlockingQueue_bench.cc new file mode 100644 index 0000000..bd65bfa --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/BlockingQueue_bench.cc @@ -0,0 +1,106 @@ +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include +#include +#include + +class Bench +{ + public: + Bench(int numThreads) + : latch_(numThreads) + { + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Bench::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + muduo::Timestamp now(muduo::Timestamp::now()); + queue_.put(now); + usleep(1000); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put(muduo::Timestamp::invalid()); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + std::map delays; + latch_.countDown(); + bool running = true; + while (running) + { + muduo::Timestamp t(queue_.take()); + muduo::Timestamp now(muduo::Timestamp::now()); + if (t.valid()) + { + int delay = static_cast(timeDifference(now, t) * 1000000); + // printf("tid=%d, latency = %d us\n", + // muduo::CurrentThread::tid(), delay); + ++delays[delay]; + } + running = t.valid(); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + for (const auto& delay : delays) + { + printf("tid = %d, delay = %d, count = %d\n", + muduo::CurrentThread::tid(), + delay.first, delay.second); + } + } + + muduo::BlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +int main(int argc, char* argv[]) +{ + int threads = argc > 1 ? atoi(argv[1]) : 1; + + Bench t(threads); + t.run(10000); + t.joinAll(); +} diff --git a/include/Third_Lib/muduo/base/tests/BlockingQueue_test.cc b/include/Third_Lib/muduo/base/tests/BlockingQueue_test.cc new file mode 100644 index 0000000..413fbd2 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/BlockingQueue_test.cc @@ -0,0 +1,106 @@ +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" + +#include +#include +#include +#include +#include + +class Test +{ + public: + Test(int numThreads) + : latch_(numThreads) + { + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Test::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "hello %d", i); + queue_.put(buf); + printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put("stop"); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + latch_.countDown(); + bool running = true; + while (running) + { + std::string d(queue_.take()); + printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); + running = (d != "stop"); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + } + + muduo::BlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +void testMove() +{ + muduo::BlockingQueue> queue; + queue.put(std::unique_ptr(new int(42))); + std::unique_ptr x = queue.take(); + printf("took %d\n", *x); + *x = 123; + queue.put(std::move(x)); + std::unique_ptr y = queue.take(); + printf("took %d\n", *y); +} + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + Test t(5); + t.run(100); + t.joinAll(); + + testMove(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/Third_Lib/muduo/base/tests/BoundedBlockingQueue_test.cc b/include/Third_Lib/muduo/base/tests/BoundedBlockingQueue_test.cc new file mode 100644 index 0000000..49f57fb --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/BoundedBlockingQueue_test.cc @@ -0,0 +1,110 @@ +#include "muduo/base/BoundedBlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" + +#include +#include + +#include +#include + +class Test +{ + public: + Test(int numThreads) + : queue_(20), + latch_(numThreads) + { + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Test::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "hello %d", i); + queue_.put(buf); + printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put("stop"); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + latch_.countDown(); + bool running = true; + while (running) + { + std::string d(queue_.take()); + printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); + running = (d != "stop"); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + } + + muduo::BoundedBlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +void testMove() +{ +#if BOOST_VERSION >= 105500L + muduo::BoundedBlockingQueue> queue(10); + queue.put(std::unique_ptr(new int(42))); + std::unique_ptr x = queue.take(); + printf("took %d\n", *x); + *x = 123; + queue.put(std::move(x)); + std::unique_ptr y; + y = queue.take(); + printf("took %d\n", *y); +#endif +} + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + testMove(); + Test t(5); + t.run(100); + t.joinAll(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/Third_Lib/muduo/base/tests/CMakeLists.txt b/include/Third_Lib/muduo/base/tests/CMakeLists.txt new file mode 100644 index 0000000..01a1c7a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/CMakeLists.txt @@ -0,0 +1,86 @@ +add_executable(asynclogging_test AsyncLogging_test.cc) +target_link_libraries(asynclogging_test muduo_base) + +add_executable(atomic_unittest Atomic_unittest.cc) +add_test(NAME atomic_unittest COMMAND atomic_unittest) + +add_executable(blockingqueue_test BlockingQueue_test.cc) +target_link_libraries(blockingqueue_test muduo_base) + +add_executable(blockingqueue_bench BlockingQueue_bench.cc) +target_link_libraries(blockingqueue_bench muduo_base) + +add_executable(boundedblockingqueue_test BoundedBlockingQueue_test.cc) +target_link_libraries(boundedblockingqueue_test muduo_base) + +add_executable(date_unittest Date_unittest.cc) +target_link_libraries(date_unittest muduo_base) +add_test(NAME date_unittest COMMAND date_unittest) + +add_executable(exception_test Exception_test.cc) +target_link_libraries(exception_test muduo_base) +add_test(NAME exception_test COMMAND exception_test) + +add_executable(fileutil_test FileUtil_test.cc) +target_link_libraries(fileutil_test muduo_base) +add_test(NAME fileutil_test COMMAND fileutil_test) + +add_executable(fork_test Fork_test.cc) +target_link_libraries(fork_test muduo_base) + +if(ZLIB_FOUND) + add_executable(gzipfile_test GzipFile_test.cc) + target_link_libraries(gzipfile_test muduo_base z) + add_test(NAME gzipfile_test COMMAND gzipfile_test) +endif() + +add_executable(logfile_test LogFile_test.cc) +target_link_libraries(logfile_test muduo_base) + +add_executable(logging_test Logging_test.cc) +target_link_libraries(logging_test muduo_base) + +add_executable(logstream_bench LogStream_bench.cc) +target_link_libraries(logstream_bench muduo_base) + +if(BOOSTTEST_LIBRARY) +add_executable(logstream_test LogStream_test.cc) +target_link_libraries(logstream_test muduo_base boost_unit_test_framework) +add_test(NAME logstream_test COMMAND logstream_test) +endif() + +add_executable(mutex_test Mutex_test.cc) +target_link_libraries(mutex_test muduo_base) + +add_executable(processinfo_test ProcessInfo_test.cc) +target_link_libraries(processinfo_test muduo_base) + +add_executable(singleton_test Singleton_test.cc) +target_link_libraries(singleton_test muduo_base) + +add_executable(singleton_threadlocal_test SingletonThreadLocal_test.cc) +target_link_libraries(singleton_threadlocal_test muduo_base) + +add_executable(thread_bench Thread_bench.cc) +target_link_libraries(thread_bench muduo_base) + +add_executable(thread_test Thread_test.cc) +target_link_libraries(thread_test muduo_base) + +add_executable(threadlocal_test ThreadLocal_test.cc) +target_link_libraries(threadlocal_test muduo_base) + +add_executable(threadlocalsingleton_test ThreadLocalSingleton_test.cc) +target_link_libraries(threadlocalsingleton_test muduo_base) + +add_executable(threadpool_test ThreadPool_test.cc) +target_link_libraries(threadpool_test muduo_base) + +add_executable(timestamp_unittest Timestamp_unittest.cc) +target_link_libraries(timestamp_unittest muduo_base) +add_test(NAME timestamp_unittest COMMAND timestamp_unittest) + +add_executable(timezone_unittest TimeZone_unittest.cc) +target_link_libraries(timezone_unittest muduo_base) +add_test(NAME timezone_unittest COMMAND timezone_unittest) + diff --git a/include/Third_Lib/muduo/base/tests/Date_unittest.cc b/include/Third_Lib/muduo/base/tests/Date_unittest.cc new file mode 100644 index 0000000..bf2d386 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Date_unittest.cc @@ -0,0 +1,88 @@ +#include "muduo/base/Date.h" +#include +#include + +using muduo::Date; + +const int kMonthsOfYear = 12; + +int isLeapYear(int year) +{ + if (year % 400 == 0) + return 1; + else if (year % 100 == 0) + return 0; + else if (year % 4 == 0) + return 1; + else + return 0; +} + +int daysOfMonth(int year, int month) +{ + static int days[2][kMonthsOfYear+1] = + { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + }; + return days[isLeapYear(year)][month]; +} + +void passByConstReference(const Date& x) +{ + printf("%s\n", x.toIsoString().c_str()); +} + +void passByValue(Date x) +{ + printf("%s\n", x.toIsoString().c_str()); +} + +int main() +{ + time_t now = time(NULL); + struct tm t1 = *gmtime(&now); + struct tm t2 = *localtime(&now); + Date someDay(2008, 9, 10); + printf("%s\n", someDay.toIsoString().c_str()); + passByValue(someDay); + passByConstReference(someDay); + Date todayUtc(t1); + printf("%s\n", todayUtc.toIsoString().c_str()); + Date todayLocal(t2); + printf("%s\n", todayLocal.toIsoString().c_str()); + + int julianDayNumber = 2415021; + int weekDay = 1; // Monday + + for (int year = 1900; year < 2500; ++year) + { + assert(Date(year, 3, 1).julianDayNumber() - Date(year, 2, 29).julianDayNumber() + == isLeapYear(year)); + for (int month = 1; month <= kMonthsOfYear; ++month) + { + for (int day = 1; day <= daysOfMonth(year, month); ++day) + { + Date d(year, month, day); + // printf("%s %d\n", d.toString().c_str(), d.weekDay()); + assert(year == d.year()); + assert(month == d.month()); + assert(day == d.day()); + assert(weekDay == d.weekDay()); + assert(julianDayNumber == d.julianDayNumber()); + + Date d2(julianDayNumber); + assert(year == d2.year()); + assert(month == d2.month()); + assert(day == d2.day()); + assert(weekDay == d2.weekDay()); + assert(julianDayNumber == d2.julianDayNumber()); + + ++julianDayNumber; + weekDay = (weekDay+1) % 7; + } + } + } + printf("All passed.\n"); +} + diff --git a/include/Third_Lib/muduo/base/tests/Exception_test.cc b/include/Third_Lib/muduo/base/tests/Exception_test.cc new file mode 100644 index 0000000..7fd8004 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Exception_test.cc @@ -0,0 +1,51 @@ +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Exception.h" +#include +#include +#include + +class Bar +{ + public: + void test(std::vector names = {}) + { + printf("Stack:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + [] { + printf("Stack inside lambda:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + }(); + std::function func([] { + printf("Stack inside std::function:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + }); + func(); + + func = std::bind(&Bar::callback, this); + func(); + + throw muduo::Exception("oops"); + } + + private: + void callback() + { + printf("Stack inside std::bind:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + } +}; + +void foo() +{ + Bar b; + b.test(); +} + +int main() +{ + try + { + foo(); + } + catch (const muduo::Exception& ex) + { + printf("reason: %s\n", ex.what()); + printf("stack trace:\n%s\n", ex.stackTrace()); + } +} diff --git a/include/Third_Lib/muduo/base/tests/FileUtil_test.cc b/include/Third_Lib/muduo/base/tests/FileUtil_test.cc new file mode 100644 index 0000000..9abe299 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/FileUtil_test.cc @@ -0,0 +1,30 @@ +#include "muduo/base/FileUtil.h" + +#include +#define __STDC_FORMAT_MACROS +#include + +using namespace muduo; + +int main() +{ + string result; + int64_t size = 0; + int err = FileUtil::readFile("/proc/self", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/proc/self", 1024, &result, NULL); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/proc/self/cmdline", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/null", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/notexist", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 102400, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 102400, &result, NULL); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); +} + diff --git a/include/Third_Lib/muduo/base/tests/Fork_test.cc b/include/Third_Lib/muduo/base/tests/Fork_test.cc new file mode 100644 index 0000000..6a3cba6 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Fork_test.cc @@ -0,0 +1,46 @@ +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +namespace +{ +__thread int x = 0; +} + +void print() +{ + printf("pid=%d tid=%d x=%d\n", getpid(), muduo::CurrentThread::tid(), x); +} + +int main() +{ + printf("parent %d\n", getpid()); + print(); + x = 1; + print(); + pid_t p = fork(); + + if (p == 0) + { + printf("chlid %d\n", getpid()); + // child + print(); + x = 2; + print(); + + if (fork() == 0) + { + printf("grandchlid %d\n", getpid()); + print(); + x = 3; + print(); + } + } + else + { + // parent + print(); + } +} diff --git a/include/Third_Lib/muduo/base/tests/GzipFile_test.cc b/include/Third_Lib/muduo/base/tests/GzipFile_test.cc new file mode 100644 index 0000000..d3f9cc3 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/GzipFile_test.cc @@ -0,0 +1,54 @@ +#include "muduo/base/GzipFile.h" + +#include "muduo/base/Logging.h" + +int main() +{ + const char* filename = "/tmp/gzipfile_test.gz"; + ::unlink(filename); + const char data[] = "123456789012345678901234567890123456789012345678901234567890\n"; + { + muduo::GzipFile writer = muduo::GzipFile::openForAppend(filename); + if (writer.valid()) + { + LOG_INFO << "tell " << writer.tell(); + LOG_INFO << "wrote " << writer.write(data); + LOG_INFO << "tell " << writer.tell(); + } + } + + { + printf("testing reader\n"); + muduo::GzipFile reader = muduo::GzipFile::openForRead(filename); + if (reader.valid()) + { + char buf[256]; + LOG_INFO << "tell " << reader.tell(); + int nr = reader.read(buf, sizeof buf); + printf("read %d\n", nr); + if (nr >= 0) + { + buf[nr] = '\0'; + printf("data %s", buf); + } + LOG_INFO << "tell " << reader.tell(); + if (strncmp(buf, data, strlen(data)) != 0) + { + printf("failed!!!\n"); + abort(); + } + else + { + printf("PASSED\n"); + } + } + } + + { + muduo::GzipFile writer = muduo::GzipFile::openForWriteExclusive(filename); + if (writer.valid() || errno != EEXIST) + { + printf("FAILED\n"); + } + } +} diff --git a/include/Third_Lib/muduo/base/tests/LogFile_test.cc b/include/Third_Lib/muduo/base/tests/LogFile_test.cc new file mode 100644 index 0000000..a0b753a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/LogFile_test.cc @@ -0,0 +1,34 @@ +#include "muduo/base/LogFile.h" +#include "muduo/base/Logging.h" + +#include + +std::unique_ptr g_logFile; + +void outputFunc(const char* msg, int len) +{ + g_logFile->append(msg, len); +} + +void flushFunc() +{ + g_logFile->flush(); +} + +int main(int argc, char* argv[]) +{ + char name[256] = { '\0' }; + strncpy(name, argv[0], sizeof name - 1); + g_logFile.reset(new muduo::LogFile(::basename(name), 200*1000)); + muduo::Logger::setOutput(outputFunc); + muduo::Logger::setFlush(flushFunc); + + muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; + + for (int i = 0; i < 10000; ++i) + { + LOG_INFO << line << i; + + usleep(1000); + } +} diff --git a/include/Third_Lib/muduo/base/tests/LogStream_bench.cc b/include/Third_Lib/muduo/base/tests/LogStream_bench.cc new file mode 100644 index 0000000..c91637a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/LogStream_bench.cc @@ -0,0 +1,82 @@ +#include "muduo/base/LogStream.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +using namespace muduo; + +const size_t N = 1000000; + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +template +void benchPrintf(const char* fmt) +{ + char buf[32]; + Timestamp start(Timestamp::now()); + for (size_t i = 0; i < N; ++i) + snprintf(buf, sizeof buf, fmt, (T)(i)); + Timestamp end(Timestamp::now()); + + printf("benchPrintf %f\n", timeDifference(end, start)); +} + +template +void benchStringStream() +{ + Timestamp start(Timestamp::now()); + std::ostringstream os; + + for (size_t i = 0; i < N; ++i) + { + os << (T)(i); + os.seekp(0, std::ios_base::beg); + } + Timestamp end(Timestamp::now()); + + printf("benchStringStream %f\n", timeDifference(end, start)); +} + +template +void benchLogStream() +{ + Timestamp start(Timestamp::now()); + LogStream os; + for (size_t i = 0; i < N; ++i) + { + os << (T)(i); + os.resetBuffer(); + } + Timestamp end(Timestamp::now()); + + printf("benchLogStream %f\n", timeDifference(end, start)); +} + +int main() +{ + benchPrintf("%d"); + + puts("int"); + benchPrintf("%d"); + benchStringStream(); + benchLogStream(); + + puts("double"); + benchPrintf("%.12g"); + benchStringStream(); + benchLogStream(); + + puts("int64_t"); + benchPrintf("%" PRId64); + benchStringStream(); + benchLogStream(); + + puts("void*"); + benchPrintf("%p"); + benchStringStream(); + benchLogStream(); + +} diff --git a/include/Third_Lib/muduo/base/tests/LogStream_test.cc b/include/Third_Lib/muduo/base/tests/LogStream_test.cc new file mode 100644 index 0000000..b6070e1 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/LogStream_test.cc @@ -0,0 +1,286 @@ +#include "muduo/base/LogStream.h" + +#include +#include + +//#define BOOST_TEST_MODULE LogStreamTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; + +BOOST_AUTO_TEST_CASE(testLogStreamBooleans) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + BOOST_CHECK_EQUAL(buf.toString(), string("")); + os << true; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os << '\n'; + BOOST_CHECK_EQUAL(buf.toString(), string("1\n")); + os << false; + BOOST_CHECK_EQUAL(buf.toString(), string("1\n0")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamIntegers) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + BOOST_CHECK_EQUAL(buf.toString(), string("")); + os << 1; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os << 0; + BOOST_CHECK_EQUAL(buf.toString(), string("10")); + os << -1; + BOOST_CHECK_EQUAL(buf.toString(), string("10-1")); + os.resetBuffer(); + + os << 0 << " " << 123 << 'x' << 0x64; + BOOST_CHECK_EQUAL(buf.toString(), string("0 123x100")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamIntegerLimits) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + os << -2147483647; + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647")); + os << static_cast(-2147483647 - 1); + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648")); + os << ' '; + os << 2147483647; + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648 2147483647")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-32768")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("32767")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("65535")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483648")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("2147483647")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("4294967295")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-9223372036854775808")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("9223372036854775807")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("18446744073709551615")); + os.resetBuffer(); + + int16_t a = 0; + int32_t b = 0; + int64_t c = 0; + os << a; + os << b; + os << c; + BOOST_CHECK_EQUAL(buf.toString(), string("000")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamFloats) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << 0.0; + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << 1.0; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os.resetBuffer(); + + os << 0.1; + BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); + os.resetBuffer(); + + os << 0.05; + BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); + os.resetBuffer(); + + os << 0.15; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + double a = 0.1; + os << a; + BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); + os.resetBuffer(); + + double b = 0.05; + os << b; + BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); + os.resetBuffer(); + + double c = 0.15; + os << c; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + os << a+b; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + BOOST_CHECK(a+b != c); + + os << 1.23456789; + BOOST_CHECK_EQUAL(buf.toString(), string("1.23456789")); + os.resetBuffer(); + + os << 1.234567; + BOOST_CHECK_EQUAL(buf.toString(), string("1.234567")); + os.resetBuffer(); + + os << -123.456; + BOOST_CHECK_EQUAL(buf.toString(), string("-123.456")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamVoid) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << static_cast(0); + BOOST_CHECK_EQUAL(buf.toString(), string("0x0")); + os.resetBuffer(); + + os << reinterpret_cast(8888); + BOOST_CHECK_EQUAL(buf.toString(), string("0x22B8")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamStrings) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << "Hello "; + BOOST_CHECK_EQUAL(buf.toString(), string("Hello ")); + + string chenshuo = "Shuo Chen"; + os << chenshuo; + BOOST_CHECK_EQUAL(buf.toString(), string("Hello Shuo Chen")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamFmts) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << muduo::Fmt("%4d", 1); + BOOST_CHECK_EQUAL(buf.toString(), string(" 1")); + os.resetBuffer(); + + os << muduo::Fmt("%4.2f", 1.2); + BOOST_CHECK_EQUAL(buf.toString(), string("1.20")); + os.resetBuffer(); + + os << muduo::Fmt("%4.2f", 1.2) << muduo::Fmt("%4d", 43); + BOOST_CHECK_EQUAL(buf.toString(), string("1.20 43")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamLong) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + for (int i = 0; i < 399; ++i) + { + os << "123456789 "; + BOOST_CHECK_EQUAL(buf.length(), 10*(i+1)); + BOOST_CHECK_EQUAL(buf.avail(), 4000 - 10*(i+1)); + } + + os << "abcdefghi "; + BOOST_CHECK_EQUAL(buf.length(), 3990); + BOOST_CHECK_EQUAL(buf.avail(), 10); + + os << "abcdefghi"; + BOOST_CHECK_EQUAL(buf.length(), 3999); + BOOST_CHECK_EQUAL(buf.avail(), 1); +} + +BOOST_AUTO_TEST_CASE(testFormatSI) +{ + BOOST_CHECK_EQUAL(muduo::formatSI(0), string("0")); + BOOST_CHECK_EQUAL(muduo::formatSI(999), string("999")); + BOOST_CHECK_EQUAL(muduo::formatSI(1000), string("1.00k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9990), string("9.99k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9994), string("9.99k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9995), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10000), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10049), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10050), string("10.1k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99900), string("99.9k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99949), string("99.9k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99950), string("100k")); + BOOST_CHECK_EQUAL(muduo::formatSI(100499), string("100k")); + // FIXME: + // BOOST_CHECK_EQUAL(muduo::formatSI(100500), string("101k")); + BOOST_CHECK_EQUAL(muduo::formatSI(100501), string("101k")); + BOOST_CHECK_EQUAL(muduo::formatSI(999499), string("999k")); + BOOST_CHECK_EQUAL(muduo::formatSI(999500), string("1.00M")); + BOOST_CHECK_EQUAL(muduo::formatSI(1004999), string("1.00M")); + // BOOST_CHECK_EQUAL(muduo::formatSI(1005000), string("1.01M")); + BOOST_CHECK_EQUAL(muduo::formatSI(1005001), string("1.01M")); + BOOST_CHECK_EQUAL(muduo::formatSI(INT64_MAX), string("9.22E")); +} + +BOOST_AUTO_TEST_CASE(testFormatIEC) +{ + BOOST_CHECK_EQUAL(muduo::formatIEC(0), string("0")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1023), string("1023")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1024), string("1.00Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10234), string("9.99Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10235), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10240), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10291), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10292), string("10.1Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102348), string("99.9Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102349), string("100Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102912), string("100Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102913), string("101Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1022976), string("999Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1047552), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1047961), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048063), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048064), string("1.00Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048576), string("1.00Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10480517), string("9.99Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10480518), string("10.0Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(INT64_MAX), string("8.00Ei")); +} diff --git a/include/Third_Lib/muduo/base/tests/Logging_test.cc b/include/Third_Lib/muduo/base/tests/Logging_test.cc new file mode 100644 index 0000000..3de5e86 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Logging_test.cc @@ -0,0 +1,122 @@ +#include "muduo/base/Logging.h" +#include "muduo/base/LogFile.h" +#include "muduo/base/ThreadPool.h" +#include "muduo/base/TimeZone.h" + +#include +#include + +int g_total; +FILE* g_file; +std::unique_ptr g_logFile; + +void dummyOutput(const char* msg, int len) +{ + g_total += len; + if (g_file) + { + fwrite(msg, 1, len, g_file); + } + else if (g_logFile) + { + g_logFile->append(msg, len); + } +} + +void bench(const char* type) +{ + muduo::Logger::setOutput(dummyOutput); + muduo::Timestamp start(muduo::Timestamp::now()); + g_total = 0; + + int n = 1000*1000; + const bool kLongLog = false; + muduo::string empty = " "; + muduo::string longStr(3000, 'X'); + longStr += " "; + for (int i = 0; i < n; ++i) + { + LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz" + << (kLongLog ? longStr : empty) + << i; + } + muduo::Timestamp end(muduo::Timestamp::now()); + double seconds = timeDifference(end, start); + printf("%12s: %f seconds, %d bytes, %10.2f msg/s, %.2f MiB/s\n", + type, seconds, g_total, n / seconds, g_total / seconds / (1024 * 1024)); +} + +void logInThread() +{ + LOG_INFO << "logInThread"; + usleep(1000); +} + +int main() +{ + getppid(); // for ltrace and strace + + muduo::ThreadPool pool("pool"); + pool.start(5); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + + LOG_TRACE << "trace"; + LOG_DEBUG << "debug"; + LOG_INFO << "Hello"; + LOG_WARN << "World"; + LOG_ERROR << "Error"; + LOG_INFO << sizeof(muduo::Logger); + LOG_INFO << sizeof(muduo::LogStream); + LOG_INFO << sizeof(muduo::Fmt); + LOG_INFO << sizeof(muduo::LogStream::Buffer); + + sleep(1); + bench("nop"); + + char buffer[64*1024]; + + g_file = fopen("/dev/null", "w"); + setbuffer(g_file, buffer, sizeof buffer); + bench("/dev/null"); + fclose(g_file); + + g_file = fopen("/tmp/log", "w"); + setbuffer(g_file, buffer, sizeof buffer); + bench("/tmp/log"); + fclose(g_file); + + g_file = NULL; + g_logFile.reset(new muduo::LogFile("test_log_st", 500*1000*1000, false)); + bench("test_log_st"); + + g_logFile.reset(new muduo::LogFile("test_log_mt", 500*1000*1000, true)); + bench("test_log_mt"); + g_logFile.reset(); + + { + g_file = stdout; + sleep(1); + muduo::TimeZone beijing(8*3600, "CST"); + muduo::Logger::setTimeZone(beijing); + LOG_TRACE << "trace CST"; + LOG_DEBUG << "debug CST"; + LOG_INFO << "Hello CST"; + LOG_WARN << "World CST"; + LOG_ERROR << "Error CST"; + + sleep(1); + muduo::TimeZone newyork("/usr/share/zoneinfo/America/New_York"); + muduo::Logger::setTimeZone(newyork); + LOG_TRACE << "trace NYT"; + LOG_DEBUG << "debug NYT"; + LOG_INFO << "Hello NYT"; + LOG_WARN << "World NYT"; + LOG_ERROR << "Error NYT"; + g_file = NULL; + } + bench("timezone nop"); +} diff --git a/include/Third_Lib/muduo/base/tests/Mutex_test.cc b/include/Third_Lib/muduo/base/tests/Mutex_test.cc new file mode 100644 index 0000000..0c22d71 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Mutex_test.cc @@ -0,0 +1,82 @@ +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include + +using namespace muduo; +using namespace std; + +MutexLock g_mutex; +vector g_vec; +const int kCount = 10*1000*1000; + +void threadFunc() +{ + for (int i = 0; i < kCount; ++i) + { + MutexLockGuard lock(g_mutex); + g_vec.push_back(i); + } +} + +int foo() __attribute__ ((noinline)); + +int g_count = 0; +int foo() +{ + MutexLockGuard lock(g_mutex); + if (!g_mutex.isLockedByThisThread()) + { + printf("FAIL\n"); + return -1; + } + + ++g_count; + return 0; +} + +int main() +{ + MCHECK(foo()); + if (g_count != 1) + { + printf("MCHECK calls twice.\n"); + abort(); + } + + const int kMaxThreads = 8; + g_vec.reserve(kMaxThreads * kCount); + + Timestamp start(Timestamp::now()); + for (int i = 0; i < kCount; ++i) + { + g_vec.push_back(i); + } + + printf("single thread without lock %f\n", timeDifference(Timestamp::now(), start)); + + start = Timestamp::now(); + threadFunc(); + printf("single thread with lock %f\n", timeDifference(Timestamp::now(), start)); + + for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads) + { + std::vector> threads; + g_vec.clear(); + start = Timestamp::now(); + for (int i = 0; i < nthreads; ++i) + { + threads.emplace_back(new Thread(&threadFunc)); + threads.back()->start(); + } + for (int i = 0; i < nthreads; ++i) + { + threads[i]->join(); + } + printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start)); + } +} + diff --git a/include/Third_Lib/muduo/base/tests/ProcessInfo_test.cc b/include/Third_Lib/muduo/base/tests/ProcessInfo_test.cc new file mode 100644 index 0000000..6e30bad --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ProcessInfo_test.cc @@ -0,0 +1,17 @@ +#include "muduo/base/ProcessInfo.h" +#include +#define __STDC_FORMAT_MACROS +#include + +int main() +{ + printf("pid = %d\n", muduo::ProcessInfo::pid()); + printf("uid = %d\n", muduo::ProcessInfo::uid()); + printf("euid = %d\n", muduo::ProcessInfo::euid()); + printf("start time = %s\n", muduo::ProcessInfo::startTime().toFormattedString().c_str()); + printf("hostname = %s\n", muduo::ProcessInfo::hostname().c_str()); + printf("opened files = %d\n", muduo::ProcessInfo::openedFiles()); + printf("threads = %zd\n", muduo::ProcessInfo::threads().size()); + printf("num threads = %d\n", muduo::ProcessInfo::numThreads()); + printf("status = %s\n", muduo::ProcessInfo::procStatus().c_str()); +} diff --git a/include/Third_Lib/muduo/base/tests/SingletonThreadLocal_test.cc b/include/Third_Lib/muduo/base/tests/SingletonThreadLocal_test.cc new file mode 100644 index 0000000..29edf6c --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/SingletonThreadLocal_test.cc @@ -0,0 +1,58 @@ +#include "muduo/base/Singleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/ThreadLocal.h" +#include "muduo/base/Thread.h" + +#include +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +#define STL muduo::Singleton >::instance().value() + +void print() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &STL, + STL.name().c_str()); +} + +void threadFunc(const char* changeTo) +{ + print(); + STL.setName(changeTo); + sleep(1); + print(); +} + +int main() +{ + STL.setName("main one"); + muduo::Thread t1(std::bind(threadFunc, "thread1")); + muduo::Thread t2(std::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + print(); + t2.join(); + pthread_exit(0); +} diff --git a/include/Third_Lib/muduo/base/tests/Singleton_test.cc b/include/Third_Lib/muduo/base/tests/Singleton_test.cc new file mode 100644 index 0000000..124d7f7 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Singleton_test.cc @@ -0,0 +1,65 @@ +#include "muduo/base/Singleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +class TestNoDestroy : muduo::noncopyable +{ + public: + // Tag member for Singleton + void no_destroy(); + + TestNoDestroy() + { + printf("tid=%d, constructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); + } + + ~TestNoDestroy() + { + printf("tid=%d, destructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); + } +}; + +void threadFunc() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); + muduo::Singleton::instance().setName("only one, changed"); +} + +int main() +{ + muduo::Singleton::instance().setName("only one"); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); + muduo::Singleton::instance(); + printf("with valgrind, you should see %zd-byte memory leak.\n", sizeof(TestNoDestroy)); +} diff --git a/include/Third_Lib/muduo/base/tests/ThreadLocalSingleton_test.cc b/include/Third_Lib/muduo/base/tests/ThreadLocalSingleton_test.cc new file mode 100644 index 0000000..efe485a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ThreadLocalSingleton_test.cc @@ -0,0 +1,58 @@ +#include "muduo/base/ThreadLocalSingleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +void threadFunc(const char* changeTo) +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + muduo::ThreadLocalSingleton::instance().setName(changeTo); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + + // no need to manually delete it + // muduo::ThreadLocalSingleton::destroy(); +} + +int main() +{ + muduo::ThreadLocalSingleton::instance().setName("main one"); + muduo::Thread t1(std::bind(threadFunc, "thread1")); + muduo::Thread t2(std::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + t2.join(); + + pthread_exit(0); +} diff --git a/include/Third_Lib/muduo/base/tests/ThreadLocal_test.cc b/include/Third_Lib/muduo/base/tests/ThreadLocal_test.cc new file mode 100644 index 0000000..a5b89cf --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ThreadLocal_test.cc @@ -0,0 +1,61 @@ +#include "muduo/base/ThreadLocal.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +muduo::ThreadLocal testObj1; +muduo::ThreadLocal testObj2; + +void print() +{ + printf("tid=%d, obj1 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj1.value(), + testObj1.value().name().c_str()); + printf("tid=%d, obj2 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj2.value(), + testObj2.value().name().c_str()); +} + +void threadFunc() +{ + print(); + testObj1.value().setName("changed 1"); + testObj2.value().setName("changed 42"); + print(); +} + +int main() +{ + testObj1.value().setName("main one"); + print(); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + testObj2.value().setName("main two"); + print(); + + pthread_exit(0); +} diff --git a/include/Third_Lib/muduo/base/tests/ThreadPool_test.cc b/include/Third_Lib/muduo/base/tests/ThreadPool_test.cc new file mode 100644 index 0000000..de0dd60 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ThreadPool_test.cc @@ -0,0 +1,97 @@ +#include "muduo/base/ThreadPool.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Logging.h" + +#include +#include // usleep + +void print() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void printString(const std::string& str) +{ + LOG_INFO << str; + usleep(100*1000); +} + +void test(int maxSize) +{ + LOG_WARN << "Test ThreadPool with max queue size = " << maxSize; + muduo::ThreadPool pool("MainThreadPool"); + pool.setMaxQueueSize(maxSize); + pool.start(5); + + LOG_WARN << "Adding"; + pool.run(print); + pool.run(print); + for (int i = 0; i < 100; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "task %d", i); + pool.run(std::bind(printString, std::string(buf))); + } + LOG_WARN << "Done"; + + muduo::CountDownLatch latch(1); + pool.run(std::bind(&muduo::CountDownLatch::countDown, &latch)); + latch.wait(); + pool.stop(); +} + +/* + * Wish we could do this in the future. +void testMove() +{ + muduo::ThreadPool pool; + pool.start(2); + + std::unique_ptr x(new int(42)); + pool.run([y = std::move(x)]{ printf("%d: %d\n", muduo::CurrentThread::tid(), *y); }); + pool.stop(); +} +*/ + +void longTask(int num) +{ + LOG_INFO << "longTask " << num; + muduo::CurrentThread::sleepUsec(3000000); +} + +void test2() +{ + LOG_WARN << "Test ThreadPool by stoping early."; + muduo::ThreadPool pool("ThreadPool"); + pool.setMaxQueueSize(5); + pool.start(3); + + muduo::Thread thread1([&pool]() + { + for (int i = 0; i < 20; ++i) + { + pool.run(std::bind(longTask, i)); + } + }, "thread1"); + thread1.start(); + + muduo::CurrentThread::sleepUsec(5000000); + LOG_WARN << "stop pool"; + pool.stop(); // early stop + + thread1.join(); + // run() after stop() + pool.run(print); + LOG_WARN << "test2 Done"; +} + +int main() +{ + test(0); + test(1); + test(5); + test(10); + test(50); + test2(); +} diff --git a/include/Third_Lib/muduo/base/tests/Thread_bench.cc b/include/Third_Lib/muduo/base/tests/Thread_bench.cc new file mode 100644 index 0000000..ae3d49c --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Thread_bench.cc @@ -0,0 +1,86 @@ +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include +#include +#include + +muduo::MutexLock g_mutex; +std::map g_delays; + +void threadFunc() +{ + //printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void threadFunc2(muduo::Timestamp start) +{ + muduo::Timestamp now(muduo::Timestamp::now()); + int delay = static_cast(timeDifference(now, start) * 1000000); + muduo::MutexLockGuard lock(g_mutex); + ++g_delays[delay]; +} + +void forkBench() +{ + sleep(10); + muduo::Timestamp start(muduo::Timestamp::now()); + int kProcesses = 10*1000; + + for (int i = 0; i < kProcesses; ++i) + { + pid_t child = fork(); + if (child == 0) + { + exit(0); + } + else + { + waitpid(child, NULL, 0); + } + } + + double timeUsed = timeDifference(muduo::Timestamp::now(), start); + printf("process creation time used %f us\n", timeUsed*1000000/kProcesses); + printf("number of created processes %d\n", kProcesses); +} + +int main(int argc, char* argv[]) +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + muduo::Timestamp start(muduo::Timestamp::now()); + + int kThreads = 100*1000; + for (int i = 0; i < kThreads; ++i) + { + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + } + + double timeUsed = timeDifference(muduo::Timestamp::now(), start); + printf("thread creation time %f us\n", timeUsed*1000000/kThreads); + printf("number of created threads %d\n", muduo::Thread::numCreated()); + + for (int i = 0; i < kThreads; ++i) + { + muduo::Timestamp now(muduo::Timestamp::now()); + muduo::Thread t2(std::bind(threadFunc2, now)); + t2.start(); + t2.join(); + } + { + muduo::MutexLockGuard lock(g_mutex); + for (const auto& delay : g_delays) + { + printf("delay = %d, count = %d\n", + delay.first, delay.second); + } + } + + forkBench(); +} diff --git a/include/Third_Lib/muduo/base/tests/Thread_test.cc b/include/Third_Lib/muduo/base/tests/Thread_test.cc new file mode 100644 index 0000000..d6e78b9 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Thread_test.cc @@ -0,0 +1,91 @@ +#include "muduo/base/Thread.h" +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +void mysleep(int seconds) +{ + timespec t = { seconds, 0 }; + nanosleep(&t, NULL); +} + +void threadFunc() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void threadFunc2(int x) +{ + printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x); +} + +void threadFunc3() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); + mysleep(1); +} + +class Foo +{ + public: + explicit Foo(double x) + : x_(x) + { + } + + void memberFunc() + { + printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_); + } + + void memberFunc2(const std::string& text) + { + printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str()); + } + + private: + double x_; +}; + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + + muduo::Thread t1(threadFunc); + t1.start(); + printf("t1.tid=%d\n", t1.tid()); + t1.join(); + + muduo::Thread t2(std::bind(threadFunc2, 42), + "thread for free function with argument"); + t2.start(); + printf("t2.tid=%d\n", t2.tid()); + t2.join(); + + Foo foo(87.53); + muduo::Thread t3(std::bind(&Foo::memberFunc, &foo), + "thread for member function without argument"); + t3.start(); + t3.join(); + + muduo::Thread t4(std::bind(&Foo::memberFunc2, std::ref(foo), std::string("Shuo Chen"))); + t4.start(); + t4.join(); + + { + muduo::Thread t5(threadFunc3); + t5.start(); + // t5 may destruct eariler than thread creation. + } + mysleep(2); + { + muduo::Thread t6(threadFunc3); + t6.start(); + mysleep(2); + // t6 destruct later than thread creation. + } + sleep(2); + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/Third_Lib/muduo/base/tests/TimeZone_unittest.cc b/include/Third_Lib/muduo/base/tests/TimeZone_unittest.cc new file mode 100644 index 0000000..5d1de82 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/TimeZone_unittest.cc @@ -0,0 +1,276 @@ +#include "muduo/base/TimeZone.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +using muduo::TimeZone; + +struct tm getTm(int year, int month, int day, + int hour, int minute, int seconds) +{ + struct tm gmt; + muduo::memZero(&gmt, sizeof gmt); + gmt.tm_year = year - 1900; + gmt.tm_mon = month - 1; + gmt.tm_mday = day; + gmt.tm_hour = hour; + gmt.tm_min = minute; + gmt.tm_sec = seconds; + return gmt; +} + +struct tm getTm(const char* str) +{ + struct tm gmt; + muduo::memZero(&gmt, sizeof gmt); + strptime(str, "%F %T", &gmt); + return gmt; +} + +time_t getGmt(int year, int month, int day, + int hour, int minute, int seconds) +{ + struct tm gmt = getTm(year, month, day, hour, minute, seconds); + return timegm(&gmt); +} + +time_t getGmt(const char* str) +{ + struct tm gmt = getTm(str); + return timegm(&gmt); +} + +struct TestCase +{ + const char* gmt; + const char* local; + bool isdst; +}; + +void test(const TimeZone& tz, TestCase tc) +{ + time_t gmt = getGmt(tc.gmt); + + { + struct tm local = tz.toLocalTime(gmt); + char buf[256]; + strftime(buf, sizeof buf, "%F %T%z(%Z)", &local); + + if (strcmp(buf, tc.local) != 0 || tc.isdst != local.tm_isdst) + { + printf("WRONG: "); + } + printf("%s -> %s\n", tc.gmt, buf); + } + + { + struct tm local = getTm(tc.local); + local.tm_isdst = tc.isdst; + time_t result = tz.fromLocalTime(local); + if (result != gmt) + { + struct tm local2 = tz.toLocalTime(result); + char buf[256]; + strftime(buf, sizeof buf, "%F %T%z(%Z)", &local2); + + printf("WRONG fromLocalTime: %ld %ld %s\n", + static_cast(gmt), static_cast(result), buf); + } + } +} + +void testNewYork() +{ + TimeZone tz("/usr/share/zoneinfo/America/New_York"); + TestCase cases[] = + { + + { "2006-03-07 00:00:00", "2006-03-06 19:00:00-0500(EST)", false }, + { "2006-04-02 06:59:59", "2006-04-02 01:59:59-0500(EST)", false }, + { "2006-04-02 07:00:00", "2006-04-02 03:00:00-0400(EDT)", true }, + { "2006-05-01 00:00:00", "2006-04-30 20:00:00-0400(EDT)", true }, + { "2006-05-02 01:00:00", "2006-05-01 21:00:00-0400(EDT)", true }, + { "2006-10-21 05:00:00", "2006-10-21 01:00:00-0400(EDT)", true }, + { "2006-10-29 05:59:59", "2006-10-29 01:59:59-0400(EDT)", true }, + { "2006-10-29 06:00:00", "2006-10-29 01:00:00-0500(EST)", false }, + { "2006-10-29 06:59:59", "2006-10-29 01:59:59-0500(EST)", false }, + { "2006-12-31 06:00:00", "2006-12-31 01:00:00-0500(EST)", false }, + { "2007-01-01 00:00:00", "2006-12-31 19:00:00-0500(EST)", false }, + + { "2007-03-07 00:00:00", "2007-03-06 19:00:00-0500(EST)", false }, + { "2007-03-11 06:59:59", "2007-03-11 01:59:59-0500(EST)", false }, + { "2007-03-11 07:00:00", "2007-03-11 03:00:00-0400(EDT)", true }, + { "2007-05-01 00:00:00", "2007-04-30 20:00:00-0400(EDT)", true }, + { "2007-05-02 01:00:00", "2007-05-01 21:00:00-0400(EDT)", true }, + { "2007-10-31 05:00:00", "2007-10-31 01:00:00-0400(EDT)", true }, + { "2007-11-04 05:59:59", "2007-11-04 01:59:59-0400(EDT)", true }, + { "2007-11-04 06:00:00", "2007-11-04 01:00:00-0500(EST)", false }, + { "2007-11-04 06:59:59", "2007-11-04 01:59:59-0500(EST)", false }, + { "2007-12-31 06:00:00", "2007-12-31 01:00:00-0500(EST)", false }, + { "2008-01-01 00:00:00", "2007-12-31 19:00:00-0500(EST)", false }, + + { "2009-03-07 00:00:00", "2009-03-06 19:00:00-0500(EST)", false }, + { "2009-03-08 06:59:59", "2009-03-08 01:59:59-0500(EST)", false }, + { "2009-03-08 07:00:00", "2009-03-08 03:00:00-0400(EDT)", true }, + { "2009-05-01 00:00:00", "2009-04-30 20:00:00-0400(EDT)", true }, + { "2009-05-02 01:00:00", "2009-05-01 21:00:00-0400(EDT)", true }, + { "2009-10-31 05:00:00", "2009-10-31 01:00:00-0400(EDT)", true }, + { "2009-11-01 05:59:59", "2009-11-01 01:59:59-0400(EDT)", true }, + { "2009-11-01 06:00:00", "2009-11-01 01:00:00-0500(EST)", false }, + { "2009-11-01 06:59:59", "2009-11-01 01:59:59-0500(EST)", false }, + { "2009-12-31 06:00:00", "2009-12-31 01:00:00-0500(EST)", false }, + { "2010-01-01 00:00:00", "2009-12-31 19:00:00-0500(EST)", false }, + + { "2010-03-13 00:00:00", "2010-03-12 19:00:00-0500(EST)", false }, + { "2010-03-14 06:59:59", "2010-03-14 01:59:59-0500(EST)", false }, + { "2010-03-14 07:00:00", "2010-03-14 03:00:00-0400(EDT)", true }, + { "2010-05-01 00:00:00", "2010-04-30 20:00:00-0400(EDT)", true }, + { "2010-05-02 01:00:00", "2010-05-01 21:00:00-0400(EDT)", true }, + { "2010-11-06 05:00:00", "2010-11-06 01:00:00-0400(EDT)", true }, + { "2010-11-07 05:59:59", "2010-11-07 01:59:59-0400(EDT)", true }, + { "2010-11-07 06:00:00", "2010-11-07 01:00:00-0500(EST)", false }, + { "2010-11-07 06:59:59", "2010-11-07 01:59:59-0500(EST)", false }, + { "2010-12-31 06:00:00", "2010-12-31 01:00:00-0500(EST)", false }, + { "2011-01-01 00:00:00", "2010-12-31 19:00:00-0500(EST)", false }, + + { "2011-03-01 00:00:00", "2011-02-28 19:00:00-0500(EST)", false }, + { "2011-03-13 06:59:59", "2011-03-13 01:59:59-0500(EST)", false }, + { "2011-03-13 07:00:00", "2011-03-13 03:00:00-0400(EDT)", true }, + { "2011-05-01 00:00:00", "2011-04-30 20:00:00-0400(EDT)", true }, + { "2011-05-02 01:00:00", "2011-05-01 21:00:00-0400(EDT)", true }, + { "2011-11-06 05:59:59", "2011-11-06 01:59:59-0400(EDT)", true }, + { "2011-11-06 06:00:00", "2011-11-06 01:00:00-0500(EST)", false }, + { "2011-11-06 06:59:59", "2011-11-06 01:59:59-0500(EST)", false }, + { "2011-12-31 06:00:00", "2011-12-31 01:00:00-0500(EST)", false }, + { "2012-01-01 00:00:00", "2011-12-31 19:00:00-0500(EST)", false }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testLondon() +{ + TimeZone tz("/usr/share/zoneinfo/Europe/London"); + TestCase cases[] = + { + + { "2011-03-26 00:00:00", "2011-03-26 00:00:00+0000(GMT)", false }, + { "2011-03-27 00:59:59", "2011-03-27 00:59:59+0000(GMT)", false }, + { "2011-03-27 01:00:00", "2011-03-27 02:00:00+0100(BST)", true }, + { "2011-10-30 00:59:59", "2011-10-30 01:59:59+0100(BST)", true }, + { "2011-10-30 01:00:00", "2011-10-30 01:00:00+0000(GMT)", false }, + { "2012-10-30 01:59:59", "2012-10-30 01:59:59+0000(GMT)", false }, + { "2011-12-31 22:00:00", "2011-12-31 22:00:00+0000(GMT)", false }, + { "2012-01-01 00:00:00", "2012-01-01 00:00:00+0000(GMT)", false }, + + { "2012-03-24 00:00:00", "2012-03-24 00:00:00+0000(GMT)", false }, + { "2012-03-25 00:59:59", "2012-03-25 00:59:59+0000(GMT)", false }, + { "2012-03-25 01:00:00", "2012-03-25 02:00:00+0100(BST)", true }, + { "2012-10-28 00:59:59", "2012-10-28 01:59:59+0100(BST)", true }, + { "2012-10-28 01:00:00", "2012-10-28 01:00:00+0000(GMT)", false }, + { "2012-10-28 01:59:59", "2012-10-28 01:59:59+0000(GMT)", false }, + { "2012-12-31 22:00:00", "2012-12-31 22:00:00+0000(GMT)", false }, + { "2013-01-01 00:00:00", "2013-01-01 00:00:00+0000(GMT)", false }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testHongKong() +{ + TimeZone tz("/usr/share/zoneinfo/Asia/Hong_Kong"); + TestCase cases[] = + { + + { "2011-04-03 00:00:00", "2011-04-03 08:00:00+0800(HKT)", false}, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testSydney() +{ + TimeZone tz("/usr/share/zoneinfo/Australia/Sydney"); + TestCase cases[] = + { + + { "2011-01-01 00:00:00", "2011-01-01 11:00:00+1100(EST)", true }, + { "2011-04-02 15:59:59", "2011-04-03 02:59:59+1100(EST)", true }, + { "2011-04-02 16:00:00", "2011-04-03 02:00:00+1000(EST)", false }, + { "2011-04-02 16:59:59", "2011-04-03 02:59:59+1000(EST)", false }, + { "2011-05-02 01:00:00", "2011-05-02 11:00:00+1000(EST)", false }, + { "2011-10-01 15:59:59", "2011-10-02 01:59:59+1000(EST)", false }, + { "2011-10-01 16:00:00", "2011-10-02 03:00:00+1100(EST)", true }, + { "2011-12-31 22:00:00", "2012-01-01 09:00:00+1100(EST)", true }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testUtc() +{ + const int kRange = 100*1000*1000; + for (time_t t = -kRange; t <= kRange; t += 11) + { + struct tm* t1 = gmtime(&t); + struct tm t2 = TimeZone::toUtcTime(t, true); + char buf1[80], buf2[80]; + strftime(buf1, sizeof buf1, "%F %T %u %j", t1); + strftime(buf2, sizeof buf2, "%F %T %u %j", &t2); + if (strcmp(buf1, buf2) != 0) + { + printf("'%s' != '%s'\n", buf1, buf2); + assert(0); + } + time_t t3 = TimeZone::fromUtcTime(t2); + if (t != t3) + { + printf("%ld != %ld\n", static_cast(t), static_cast(t3)); + assert(0); + } + } +} + +void testFixedTimezone() +{ + TimeZone tz(8*3600, "CST"); + TestCase cases[] = + { + + { "2014-04-03 00:00:00", "2014-04-03 08:00:00+0800(CST)", false}, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +int main() +{ + testNewYork(); + testLondon(); + testSydney(); + testHongKong(); + testFixedTimezone(); + testUtc(); +} diff --git a/include/Third_Lib/muduo/base/tests/Timestamp_unittest.cc b/include/Third_Lib/muduo/base/tests/Timestamp_unittest.cc new file mode 100644 index 0000000..5e27592 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Timestamp_unittest.cc @@ -0,0 +1,66 @@ +#include "muduo/base/Timestamp.h" +#include +#include + +using muduo::Timestamp; + +void passByConstReference(const Timestamp& x) +{ + printf("%s\n", x.toString().c_str()); +} + +void passByValue(Timestamp x) +{ + printf("%s\n", x.toString().c_str()); +} + +void benchmark() +{ + const int kNumber = 1000*1000; + + std::vector stamps; + stamps.reserve(kNumber); + for (int i = 0; i < kNumber; ++i) + { + stamps.push_back(Timestamp::now()); + } + printf("%s\n", stamps.front().toString().c_str()); + printf("%s\n", stamps.back().toString().c_str()); + printf("%f\n", timeDifference(stamps.back(), stamps.front())); + + int increments[100] = { 0 }; + int64_t start = stamps.front().microSecondsSinceEpoch(); + for (int i = 1; i < kNumber; ++i) + { + int64_t next = stamps[i].microSecondsSinceEpoch(); + int64_t inc = next - start; + start = next; + if (inc < 0) + { + printf("reverse!\n"); + } + else if (inc < 100) + { + ++increments[inc]; + } + else + { + printf("big gap %d\n", static_cast(inc)); + } + } + + for (int i = 0; i < 100; ++i) + { + printf("%2d: %d\n", i, increments[i]); + } +} + +int main() +{ + Timestamp now(Timestamp::now()); + printf("%s\n", now.toString().c_str()); + passByValue(now); + passByConstReference(now); + benchmark(); +} + diff --git a/include/Third_Lib/muduo/net/Acceptor.cc b/include/Third_Lib/muduo/net/Acceptor.cc new file mode 100644 index 0000000..39d0cb6 --- /dev/null +++ b/include/Third_Lib/muduo/net/Acceptor.cc @@ -0,0 +1,89 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Acceptor.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/SocketsOps.h" + +#include +#include +//#include +//#include +#include + +using namespace muduo; +using namespace muduo::net; + +Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) + : loop_(loop), + acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), + acceptChannel_(loop, acceptSocket_.fd()), + listening_(false), + idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) +{ + assert(idleFd_ >= 0); + acceptSocket_.setReuseAddr(true); + acceptSocket_.setReusePort(reuseport); + acceptSocket_.bindAddress(listenAddr); + acceptChannel_.setReadCallback( + std::bind(&Acceptor::handleRead, this)); +} + +Acceptor::~Acceptor() +{ + acceptChannel_.disableAll(); + acceptChannel_.remove(); + ::close(idleFd_); +} + +void Acceptor::listen() +{ + loop_->assertInLoopThread(); + listening_ = true; + acceptSocket_.listen(); + acceptChannel_.enableReading(); +} + +void Acceptor::handleRead() +{ + loop_->assertInLoopThread(); + InetAddress peerAddr; + //FIXME loop until no more + int connfd = acceptSocket_.accept(&peerAddr); + if (connfd >= 0) + { + // string hostport = peerAddr.toIpPort(); + // LOG_TRACE << "Accepts of " << hostport; + if (newConnectionCallback_) + { + newConnectionCallback_(connfd, peerAddr); + } + else + { + sockets::close(connfd); + } + } + else + { + LOG_SYSERR << "in Acceptor::handleRead"; + // Read the section named "The special problem of + // accept()ing when you can't" in libev's doc. + // By Marc Lehmann, author of libev. + if (errno == EMFILE) + { + ::close(idleFd_); + idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); + ::close(idleFd_); + idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); + } + } +} + diff --git a/include/Third_Lib/muduo/net/Acceptor.h b/include/Third_Lib/muduo/net/Acceptor.h new file mode 100644 index 0000000..761d073 --- /dev/null +++ b/include/Third_Lib/muduo/net/Acceptor.h @@ -0,0 +1,63 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_ACCEPTOR_H +#define MUDUO_NET_ACCEPTOR_H + +#include + +#include "muduo/net/Channel.h" +#include "muduo/net/Socket.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; +class InetAddress; + +/// +/// Acceptor of incoming TCP connections. +/// +class Acceptor : noncopyable +{ + public: + typedef std::function NewConnectionCallback; + + Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); + ~Acceptor(); + + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + + void listen(); + + bool listening() const { return listening_; } + + // Deprecated, use the correct spelling one above. + // Leave the wrong spelling here in case one needs to grep it for error messages. + // bool listenning() const { return listening(); } + + private: + void handleRead(); + + EventLoop* loop_; + Socket acceptSocket_; + Channel acceptChannel_; + NewConnectionCallback newConnectionCallback_; + bool listening_; + int idleFd_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_ACCEPTOR_H diff --git a/include/Third_Lib/muduo/net/BUILD.bazel b/include/Third_Lib/muduo/net/BUILD.bazel new file mode 100644 index 0000000..33d78d1 --- /dev/null +++ b/include/Third_Lib/muduo/net/BUILD.bazel @@ -0,0 +1,51 @@ +cc_library( + name = "net", + srcs = [ + "Acceptor.cc", + "Buffer.cc", + "Channel.cc", + "Connector.cc", + "EventLoop.cc", + "EventLoopThread.cc", + "EventLoopThreadPool.cc", + "InetAddress.cc", + "Poller.cc", + "Socket.cc", + "SocketsOps.cc", + "TcpClient.cc", + "TcpConnection.cc", + "TcpServer.cc", + "Timer.cc", + "TimerQueue.cc", + "poller/DefaultPoller.cc", + "poller/EPollPoller.cc", + "poller/PollPoller.cc", + ], + hdrs = [ + "Acceptor.h", + "Buffer.h", + "Callbacks.h", + "Channel.h", + "Connector.h", + "Endian.h", + "EventLoop.h", + "EventLoopThread.h", + "EventLoopThreadPool.h", + "InetAddress.h", + "Poller.h", + "Socket.h", + "SocketsOps.h", + "TcpClient.h", + "TcpConnection.h", + "TcpServer.h", + "Timer.h", + "TimerId.h", + "TimerQueue.h", + "poller/EPollPoller.h", + "poller/PollPoller.h", + ], + visibility = ["//visibility:public"], + deps = [ + "//muduo/base", + ], +) diff --git a/include/Third_Lib/muduo/net/Buffer.cc b/include/Third_Lib/muduo/net/Buffer.cc new file mode 100644 index 0000000..7c921fc --- /dev/null +++ b/include/Third_Lib/muduo/net/Buffer.cc @@ -0,0 +1,58 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Buffer.h" + +#include "muduo/net/SocketsOps.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +const char Buffer::kCRLF[] = "\r\n"; + +const size_t Buffer::kCheapPrepend; +const size_t Buffer::kInitialSize; + +ssize_t Buffer::readFd(int fd, int* savedErrno) +{ + // saved an ioctl()/FIONREAD call to tell how much to read + char extrabuf[65536]; + struct iovec vec[2]; + const size_t writable = writableBytes(); + vec[0].iov_base = begin()+writerIndex_; + vec[0].iov_len = writable; + vec[1].iov_base = extrabuf; + vec[1].iov_len = sizeof extrabuf; + // when there is enough space in this buffer, don't read into extrabuf. + // when extrabuf is used, we read 128k-1 bytes at most. + const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; + const ssize_t n = sockets::readv(fd, vec, iovcnt); + if (n < 0) + { + *savedErrno = errno; + } + else if (implicit_cast(n) <= writable) + { + writerIndex_ += n; + } + else + { + writerIndex_ = buffer_.size(); + append(extrabuf, n - writable); + } + // if (n == writable + sizeof extrabuf) + // { + // goto line_30; + // } + return n; +} + diff --git a/include/Third_Lib/muduo/net/Buffer.h b/include/Third_Lib/muduo/net/Buffer.h new file mode 100644 index 0000000..4fa82d4 --- /dev/null +++ b/include/Third_Lib/muduo/net/Buffer.h @@ -0,0 +1,422 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_BUFFER_H +#define MUDUO_NET_BUFFER_H + +#include "muduo/base/copyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" + +#include "muduo/net/Endian.h" + +#include +#include + +#include +#include +//#include // ssize_t + +namespace muduo +{ +namespace net +{ + +/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer +/// +/// @code +/// +-------------------+------------------+------------------+ +/// | prependable bytes | readable bytes | writable bytes | +/// | | (CONTENT) | | +/// +-------------------+------------------+------------------+ +/// | | | | +/// 0 <= readerIndex <= writerIndex <= size +/// @endcode +class Buffer : public muduo::copyable +{ + public: + static const size_t kCheapPrepend = 8; + static const size_t kInitialSize = 1024; + + explicit Buffer(size_t initialSize = kInitialSize) + : buffer_(kCheapPrepend + initialSize), + readerIndex_(kCheapPrepend), + writerIndex_(kCheapPrepend) + { + assert(readableBytes() == 0); + assert(writableBytes() == initialSize); + assert(prependableBytes() == kCheapPrepend); + } + + // implicit copy-ctor, move-ctor, dtor and assignment are fine + // NOTE: implicit move-ctor is added in g++ 4.6 + + void swap(Buffer& rhs) + { + buffer_.swap(rhs.buffer_); + std::swap(readerIndex_, rhs.readerIndex_); + std::swap(writerIndex_, rhs.writerIndex_); + } + + size_t readableBytes() const + { return writerIndex_ - readerIndex_; } + + size_t writableBytes() const + { return buffer_.size() - writerIndex_; } + + size_t prependableBytes() const + { return readerIndex_; } + + const char* peek() const + { return begin() + readerIndex_; } + + const char* findCRLF() const + { + // FIXME: replace with memmem()? + const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; + } + + const char* findCRLF(const char* start) const + { + assert(peek() <= start); + assert(start <= beginWrite()); + // FIXME: replace with memmem()? + const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; + } + + const char* findEOL() const + { + const void* eol = memchr(peek(), '\n', readableBytes()); + return static_cast(eol); + } + + const char* findEOL(const char* start) const + { + assert(peek() <= start); + assert(start <= beginWrite()); + const void* eol = memchr(start, '\n', beginWrite() - start); + return static_cast(eol); + } + + // retrieve returns void, to prevent + // string str(retrieve(readableBytes()), readableBytes()); + // the evaluation of two functions are unspecified + void retrieve(size_t len) + { + assert(len <= readableBytes()); + if (len < readableBytes()) + { + readerIndex_ += len; + } + else + { + retrieveAll(); + } + } + + void retrieveUntil(const char* end) + { + assert(peek() <= end); + assert(end <= beginWrite()); + retrieve(end - peek()); + } + + void retrieveInt64() + { + retrieve(sizeof(int64_t)); + } + + void retrieveInt32() + { + retrieve(sizeof(int32_t)); + } + + void retrieveInt16() + { + retrieve(sizeof(int16_t)); + } + + void retrieveInt8() + { + retrieve(sizeof(int8_t)); + } + + void retrieveAll() + { + readerIndex_ = kCheapPrepend; + writerIndex_ = kCheapPrepend; + } + + string retrieveAllAsString() + { + return retrieveAsString(readableBytes()); + } + + string retrieveAsString(size_t len) + { + assert(len <= readableBytes()); + string result(peek(), len); + retrieve(len); + return result; + } + + StringPiece toStringPiece() const + { + return StringPiece(peek(), static_cast(readableBytes())); + } + + void append(const StringPiece& str) + { + append(str.data(), str.size()); + } + + void append(const char* /*restrict*/ data, size_t len) + { + ensureWritableBytes(len); + std::copy(data, data+len, beginWrite()); + hasWritten(len); + } + + void append(const void* /*restrict*/ data, size_t len) + { + append(static_cast(data), len); + } + + void ensureWritableBytes(size_t len) + { + if (writableBytes() < len) + { + makeSpace(len); + } + assert(writableBytes() >= len); + } + + char* beginWrite() + { return begin() + writerIndex_; } + + const char* beginWrite() const + { return begin() + writerIndex_; } + + void hasWritten(size_t len) + { + assert(len <= writableBytes()); + writerIndex_ += len; + } + + void unwrite(size_t len) + { + assert(len <= readableBytes()); + writerIndex_ -= len; + } + + /// + /// Append int64_t using network endian + /// + void appendInt64(int64_t x) + { + int64_t be64 = sockets::hostToNetwork64(x); + append(&be64, sizeof be64); + } + + /// + /// Append int32_t using network endian + /// + void appendInt32(int32_t x) + { + int32_t be32 = sockets::hostToNetwork32(x); + append(&be32, sizeof be32); + } + + void appendInt16(int16_t x) + { + int16_t be16 = sockets::hostToNetwork16(x); + append(&be16, sizeof be16); + } + + void appendInt8(int8_t x) + { + append(&x, sizeof x); + } + + /// + /// Read int64_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int64_t readInt64() + { + int64_t result = peekInt64(); + retrieveInt64(); + return result; + } + + /// + /// Read int32_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int32_t readInt32() + { + int32_t result = peekInt32(); + retrieveInt32(); + return result; + } + + int16_t readInt16() + { + int16_t result = peekInt16(); + retrieveInt16(); + return result; + } + + int8_t readInt8() + { + int8_t result = peekInt8(); + retrieveInt8(); + return result; + } + + /// + /// Peek int64_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int64_t) + int64_t peekInt64() const + { + assert(readableBytes() >= sizeof(int64_t)); + int64_t be64 = 0; + ::memcpy(&be64, peek(), sizeof be64); + return sockets::networkToHost64(be64); + } + + /// + /// Peek int32_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int32_t peekInt32() const + { + assert(readableBytes() >= sizeof(int32_t)); + int32_t be32 = 0; + ::memcpy(&be32, peek(), sizeof be32); + return sockets::networkToHost32(be32); + } + + int16_t peekInt16() const + { + assert(readableBytes() >= sizeof(int16_t)); + int16_t be16 = 0; + ::memcpy(&be16, peek(), sizeof be16); + return sockets::networkToHost16(be16); + } + + int8_t peekInt8() const + { + assert(readableBytes() >= sizeof(int8_t)); + int8_t x = *peek(); + return x; + } + + /// + /// Prepend int64_t using network endian + /// + void prependInt64(int64_t x) + { + int64_t be64 = sockets::hostToNetwork64(x); + prepend(&be64, sizeof be64); + } + + /// + /// Prepend int32_t using network endian + /// + void prependInt32(int32_t x) + { + int32_t be32 = sockets::hostToNetwork32(x); + prepend(&be32, sizeof be32); + } + + void prependInt16(int16_t x) + { + int16_t be16 = sockets::hostToNetwork16(x); + prepend(&be16, sizeof be16); + } + + void prependInt8(int8_t x) + { + prepend(&x, sizeof x); + } + + void prepend(const void* /*restrict*/ data, size_t len) + { + assert(len <= prependableBytes()); + readerIndex_ -= len; + const char* d = static_cast(data); + std::copy(d, d+len, begin()+readerIndex_); + } + + void shrink(size_t reserve) + { + // FIXME: use vector::shrink_to_fit() in C++ 11 if possible. + Buffer other; + other.ensureWritableBytes(readableBytes()+reserve); + other.append(toStringPiece()); + swap(other); + } + + size_t internalCapacity() const + { + return buffer_.capacity(); + } + + /// Read data directly into buffer. + /// + /// It may implement with readv(2) + /// @return result of read(2), @c errno is saved + ssize_t readFd(int fd, int* savedErrno); + + private: + + char* begin() + { return &*buffer_.begin(); } + + const char* begin() const + { return &*buffer_.begin(); } + + void makeSpace(size_t len) + { + if (writableBytes() + prependableBytes() < len + kCheapPrepend) + { + // FIXME: move readable data + buffer_.resize(writerIndex_+len); + } + else + { + // move readable data to the front, make space inside buffer + assert(kCheapPrepend < readerIndex_); + size_t readable = readableBytes(); + std::copy(begin()+readerIndex_, + begin()+writerIndex_, + begin()+kCheapPrepend); + readerIndex_ = kCheapPrepend; + writerIndex_ = readerIndex_ + readable; + assert(readable == readableBytes()); + } + } + + private: + std::vector buffer_; + size_t readerIndex_; + size_t writerIndex_; + + static const char kCRLF[]; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_BUFFER_H diff --git a/include/Third_Lib/muduo/net/CMakeLists.txt b/include/Third_Lib/muduo/net/CMakeLists.txt new file mode 100644 index 0000000..7510d87 --- /dev/null +++ b/include/Third_Lib/muduo/net/CMakeLists.txt @@ -0,0 +1,69 @@ +include(CheckFunctionExists) + +check_function_exists(accept4 HAVE_ACCEPT4) +if(NOT HAVE_ACCEPT4) + set_source_files_properties(SocketsOps.cc PROPERTIES COMPILE_FLAGS "-DNO_ACCEPT4") +endif() + +set(net_SRCS + Acceptor.cc + Buffer.cc + Channel.cc + Connector.cc + EventLoop.cc + EventLoopThread.cc + EventLoopThreadPool.cc + InetAddress.cc + Poller.cc + poller/DefaultPoller.cc + poller/EPollPoller.cc + poller/PollPoller.cc + Socket.cc + SocketsOps.cc + TcpClient.cc + TcpConnection.cc + TcpServer.cc + Timer.cc + TimerQueue.cc + ) + +add_library(muduo_net ${net_SRCS}) +target_link_libraries(muduo_net muduo_base) + +#add_library(muduo_net_cpp11 ${net_SRCS}) +#target_link_libraries(muduo_net_cpp11 muduo_base_cpp11) +#set_target_properties(muduo_net_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") + +install(TARGETS muduo_net DESTINATION lib) +#install(TARGETS muduo_net_cpp11 DESTINATION lib) + +set(HEADERS + Buffer.h + Callbacks.h + Channel.h + Endian.h + EventLoop.h + EventLoopThread.h + EventLoopThreadPool.h + InetAddress.h + TcpClient.h + TcpConnection.h + TcpServer.h + TimerId.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net) + +add_subdirectory(http) +add_subdirectory(inspect) + +if(MUDUO_BUILD_EXAMPLES) + add_subdirectory(tests) +endif() + +if(PROTOBUF_FOUND) + add_subdirectory(protobuf) + add_subdirectory(protorpc) +else() + add_subdirectory(protobuf EXCLUDE_FROM_ALL) + add_subdirectory(protorpc EXCLUDE_FROM_ALL) +endif() diff --git a/include/Third_Lib/muduo/net/Callbacks.h b/include/Third_Lib/muduo/net/Callbacks.h new file mode 100644 index 0000000..443ed79 --- /dev/null +++ b/include/Third_Lib/muduo/net/Callbacks.h @@ -0,0 +1,82 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_CALLBACKS_H +#define MUDUO_NET_CALLBACKS_H + +#include "muduo/base/Timestamp.h" + +#include +#include + +namespace muduo +{ + +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; + +// should really belong to base/Types.h, but is not included there. + +template +inline T* get_pointer(const std::shared_ptr& ptr) +{ + return ptr.get(); +} + +template +inline T* get_pointer(const std::unique_ptr& ptr) +{ + return ptr.get(); +} + +// Adapted from google-protobuf stubs/common.h +// see License in muduo/base/Types.h +template +inline ::std::shared_ptr down_pointer_cast(const ::std::shared_ptr& f) { + if (false) + { + implicit_cast(0); + } + +#ifndef NDEBUG + assert(f == NULL || dynamic_cast(get_pointer(f)) != NULL); +#endif + return ::std::static_pointer_cast(f); +} + +namespace net +{ + +// All client visible callbacks go here. + +class Buffer; +class TcpConnection; +typedef std::shared_ptr TcpConnectionPtr; +typedef std::function TimerCallback; +typedef std::function ConnectionCallback; +typedef std::function CloseCallback; +typedef std::function WriteCompleteCallback; +typedef std::function HighWaterMarkCallback; + +// the data has been read to (buf, len) +typedef std::function MessageCallback; + +void defaultConnectionCallback(const TcpConnectionPtr& conn); +void defaultMessageCallback(const TcpConnectionPtr& conn, + Buffer* buffer, + Timestamp receiveTime); + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CALLBACKS_H diff --git a/include/Third_Lib/muduo/net/Channel.cc b/include/Third_Lib/muduo/net/Channel.cc new file mode 100644 index 0000000..1e9a40a --- /dev/null +++ b/include/Third_Lib/muduo/net/Channel.cc @@ -0,0 +1,146 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +const int Channel::kNoneEvent = 0; +const int Channel::kReadEvent = POLLIN | POLLPRI; +const int Channel::kWriteEvent = POLLOUT; + +Channel::Channel(EventLoop* loop, int fd__) + : loop_(loop), + fd_(fd__), + events_(0), + revents_(0), + index_(-1), + logHup_(true), + tied_(false), + eventHandling_(false), + addedToLoop_(false) +{ +} + +Channel::~Channel() +{ + assert(!eventHandling_); + assert(!addedToLoop_); + if (loop_->isInLoopThread()) + { + assert(!loop_->hasChannel(this)); + } +} + +void Channel::tie(const std::shared_ptr& obj) +{ + tie_ = obj; + tied_ = true; +} + +void Channel::update() +{ + addedToLoop_ = true; + loop_->updateChannel(this); +} + +void Channel::remove() +{ + assert(isNoneEvent()); + addedToLoop_ = false; + loop_->removeChannel(this); +} + +void Channel::handleEvent(Timestamp receiveTime) +{ + std::shared_ptr guard; + if (tied_) + { + guard = tie_.lock(); + if (guard) + { + handleEventWithGuard(receiveTime); + } + } + else + { + handleEventWithGuard(receiveTime); + } +} + +void Channel::handleEventWithGuard(Timestamp receiveTime) +{ + eventHandling_ = true; + LOG_TRACE << reventsToString(); + if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) + { + if (logHup_) + { + LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP"; + } + if (closeCallback_) closeCallback_(); + } + + if (revents_ & POLLNVAL) + { + LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL"; + } + + if (revents_ & (POLLERR | POLLNVAL)) + { + if (errorCallback_) errorCallback_(); + } + if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) + { + if (readCallback_) readCallback_(receiveTime); + } + if (revents_ & POLLOUT) + { + if (writeCallback_) writeCallback_(); + } + eventHandling_ = false; +} + +string Channel::reventsToString() const +{ + return eventsToString(fd_, revents_); +} + +string Channel::eventsToString() const +{ + return eventsToString(fd_, events_); +} + +string Channel::eventsToString(int fd, int ev) +{ + std::ostringstream oss; + oss << fd << ": "; + if (ev & POLLIN) + oss << "IN "; + if (ev & POLLPRI) + oss << "PRI "; + if (ev & POLLOUT) + oss << "OUT "; + if (ev & POLLHUP) + oss << "HUP "; + if (ev & POLLRDHUP) + oss << "RDHUP "; + if (ev & POLLERR) + oss << "ERR "; + if (ev & POLLNVAL) + oss << "NVAL "; + + return oss.str(); +} diff --git a/include/Third_Lib/muduo/net/Channel.h b/include/Third_Lib/muduo/net/Channel.h new file mode 100644 index 0000000..bafa224 --- /dev/null +++ b/include/Third_Lib/muduo/net/Channel.h @@ -0,0 +1,113 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_CHANNEL_H +#define MUDUO_NET_CHANNEL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/Timestamp.h" + +#include +#include + +namespace muduo +{ +namespace net +{ + +class EventLoop; + +/// +/// A selectable I/O channel. +/// +/// This class doesn't own the file descriptor. +/// The file descriptor could be a socket, +/// an eventfd, a timerfd, or a signalfd +class Channel : noncopyable +{ + public: + typedef std::function EventCallback; + typedef std::function ReadEventCallback; + + Channel(EventLoop* loop, int fd); + ~Channel(); + + void handleEvent(Timestamp receiveTime); + void setReadCallback(ReadEventCallback cb) + { readCallback_ = std::move(cb); } + void setWriteCallback(EventCallback cb) + { writeCallback_ = std::move(cb); } + void setCloseCallback(EventCallback cb) + { closeCallback_ = std::move(cb); } + void setErrorCallback(EventCallback cb) + { errorCallback_ = std::move(cb); } + + /// Tie this channel to the owner object managed by shared_ptr, + /// prevent the owner object being destroyed in handleEvent. + void tie(const std::shared_ptr&); + + int fd() const { return fd_; } + int events() const { return events_; } + void set_revents(int revt) { revents_ = revt; } // used by pollers + // int revents() const { return revents_; } + bool isNoneEvent() const { return events_ == kNoneEvent; } + + void enableReading() { events_ |= kReadEvent; update(); } + void disableReading() { events_ &= ~kReadEvent; update(); } + void enableWriting() { events_ |= kWriteEvent; update(); } + void disableWriting() { events_ &= ~kWriteEvent; update(); } + void disableAll() { events_ = kNoneEvent; update(); } + bool isWriting() const { return events_ & kWriteEvent; } + bool isReading() const { return events_ & kReadEvent; } + + // for Poller + int index() { return index_; } + void set_index(int idx) { index_ = idx; } + + // for debug + string reventsToString() const; + string eventsToString() const; + + void doNotLogHup() { logHup_ = false; } + + EventLoop* ownerLoop() { return loop_; } + void remove(); + + private: + static string eventsToString(int fd, int ev); + + void update(); + void handleEventWithGuard(Timestamp receiveTime); + + static const int kNoneEvent; + static const int kReadEvent; + static const int kWriteEvent; + + EventLoop* loop_; + const int fd_; + int events_; + int revents_; // it's the received event types of epoll or poll + int index_; // used by Poller. + bool logHup_; + + std::weak_ptr tie_; + bool tied_; + bool eventHandling_; + bool addedToLoop_; + ReadEventCallback readCallback_; + EventCallback writeCallback_; + EventCallback closeCallback_; + EventCallback errorCallback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CHANNEL_H diff --git a/include/Third_Lib/muduo/net/Connector.cc b/include/Third_Lib/muduo/net/Connector.cc new file mode 100644 index 0000000..0b492ad --- /dev/null +++ b/include/Third_Lib/muduo/net/Connector.cc @@ -0,0 +1,226 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Connector.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/SocketsOps.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +const int Connector::kMaxRetryDelayMs; + +Connector::Connector(EventLoop* loop, const InetAddress& serverAddr) + : loop_(loop), + serverAddr_(serverAddr), + connect_(false), + state_(kDisconnected), + retryDelayMs_(kInitRetryDelayMs) +{ + LOG_DEBUG << "ctor[" << this << "]"; +} + +Connector::~Connector() +{ + LOG_DEBUG << "dtor[" << this << "]"; + assert(!channel_); +} + +void Connector::start() +{ + connect_ = true; + loop_->runInLoop(std::bind(&Connector::startInLoop, this)); // FIXME: unsafe +} + +void Connector::startInLoop() +{ + loop_->assertInLoopThread(); + assert(state_ == kDisconnected); + if (connect_) + { + connect(); + } + else + { + LOG_DEBUG << "do not connect"; + } +} + +void Connector::stop() +{ + connect_ = false; + loop_->queueInLoop(std::bind(&Connector::stopInLoop, this)); // FIXME: unsafe + // FIXME: cancel timer +} + +void Connector::stopInLoop() +{ + loop_->assertInLoopThread(); + if (state_ == kConnecting) + { + setState(kDisconnected); + int sockfd = removeAndResetChannel(); + retry(sockfd); + } +} + +void Connector::connect() +{ + int sockfd = sockets::createNonblockingOrDie(serverAddr_.family()); + int ret = sockets::connect(sockfd, serverAddr_.getSockAddr()); + int savedErrno = (ret == 0) ? 0 : errno; + switch (savedErrno) + { + case 0: + case EINPROGRESS: + case EINTR: + case EISCONN: + connecting(sockfd); + break; + + case EAGAIN: + case EADDRINUSE: + case EADDRNOTAVAIL: + case ECONNREFUSED: + case ENETUNREACH: + retry(sockfd); + break; + + case EACCES: + case EPERM: + case EAFNOSUPPORT: + case EALREADY: + case EBADF: + case EFAULT: + case ENOTSOCK: + LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno; + sockets::close(sockfd); + break; + + default: + LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno; + sockets::close(sockfd); + // connectErrorCallback_(); + break; + } +} + +void Connector::restart() +{ + loop_->assertInLoopThread(); + setState(kDisconnected); + retryDelayMs_ = kInitRetryDelayMs; + connect_ = true; + startInLoop(); +} + +void Connector::connecting(int sockfd) +{ + setState(kConnecting); + assert(!channel_); + channel_.reset(new Channel(loop_, sockfd)); + channel_->setWriteCallback( + std::bind(&Connector::handleWrite, this)); // FIXME: unsafe + channel_->setErrorCallback( + std::bind(&Connector::handleError, this)); // FIXME: unsafe + + // channel_->tie(shared_from_this()); is not working, + // as channel_ is not managed by shared_ptr + channel_->enableWriting(); +} + +int Connector::removeAndResetChannel() +{ + channel_->disableAll(); + channel_->remove(); + int sockfd = channel_->fd(); + // Can't reset channel_ here, because we are inside Channel::handleEvent + loop_->queueInLoop(std::bind(&Connector::resetChannel, this)); // FIXME: unsafe + return sockfd; +} + +void Connector::resetChannel() +{ + channel_.reset(); +} + +void Connector::handleWrite() +{ + LOG_TRACE << "Connector::handleWrite " << state_; + + if (state_ == kConnecting) + { + int sockfd = removeAndResetChannel(); + int err = sockets::getSocketError(sockfd); + if (err) + { + LOG_WARN << "Connector::handleWrite - SO_ERROR = " + << err << " " << strerror_tl(err); + retry(sockfd); + } + else if (sockets::isSelfConnect(sockfd)) + { + LOG_WARN << "Connector::handleWrite - Self connect"; + retry(sockfd); + } + else + { + setState(kConnected); + if (connect_) + { + newConnectionCallback_(sockfd); + } + else + { + sockets::close(sockfd); + } + } + } + else + { + // what happened? + assert(state_ == kDisconnected); + } +} + +void Connector::handleError() +{ + LOG_ERROR << "Connector::handleError state=" << state_; + if (state_ == kConnecting) + { + int sockfd = removeAndResetChannel(); + int err = sockets::getSocketError(sockfd); + LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err); + retry(sockfd); + } +} + +void Connector::retry(int sockfd) +{ + sockets::close(sockfd); + setState(kDisconnected); + if (connect_) + { + LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toIpPort() + << " in " << retryDelayMs_ << " milliseconds. "; + loop_->runAfter(retryDelayMs_/1000.0, + std::bind(&Connector::startInLoop, shared_from_this())); + retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs); + } + else + { + LOG_DEBUG << "do not connect"; + } +} + diff --git a/include/Third_Lib/muduo/net/Connector.h b/include/Third_Lib/muduo/net/Connector.h new file mode 100644 index 0000000..4b79fb2 --- /dev/null +++ b/include/Third_Lib/muduo/net/Connector.h @@ -0,0 +1,74 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_CONNECTOR_H +#define MUDUO_NET_CONNECTOR_H + +#include "muduo/base/noncopyable.h" +#include "muduo/net/InetAddress.h" + +#include +#include + +namespace muduo +{ +namespace net +{ + +class Channel; +class EventLoop; + +class Connector : noncopyable, + public std::enable_shared_from_this +{ + public: + typedef std::function NewConnectionCallback; + + Connector(EventLoop* loop, const InetAddress& serverAddr); + ~Connector(); + + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + + void start(); // can be called in any thread + void restart(); // must be called in loop thread + void stop(); // can be called in any thread + + const InetAddress& serverAddress() const { return serverAddr_; } + + private: + enum States { kDisconnected, kConnecting, kConnected }; + static const int kMaxRetryDelayMs = 30*1000; + static const int kInitRetryDelayMs = 500; + + void setState(States s) { state_ = s; } + void startInLoop(); + void stopInLoop(); + void connect(); + void connecting(int sockfd); + void handleWrite(); + void handleError(); + void retry(int sockfd); + int removeAndResetChannel(); + void resetChannel(); + + EventLoop* loop_; + InetAddress serverAddr_; + bool connect_; // atomic + States state_; // FIXME: use atomic variable + std::unique_ptr channel_; + NewConnectionCallback newConnectionCallback_; + int retryDelayMs_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CONNECTOR_H diff --git a/include/Third_Lib/muduo/net/Endian.h b/include/Third_Lib/muduo/net/Endian.h new file mode 100644 index 0000000..82bd730 --- /dev/null +++ b/include/Third_Lib/muduo/net/Endian.h @@ -0,0 +1,65 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_ENDIAN_H +#define MUDUO_NET_ENDIAN_H + +#include +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ + +// the inline assembler code makes type blur, +// so we disable warnings for a while. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wold-style-cast" +inline uint64_t hostToNetwork64(uint64_t host64) +{ + return htobe64(host64); +} + +inline uint32_t hostToNetwork32(uint32_t host32) +{ + return htobe32(host32); +} + +inline uint16_t hostToNetwork16(uint16_t host16) +{ + return htobe16(host16); +} + +inline uint64_t networkToHost64(uint64_t net64) +{ + return be64toh(net64); +} + +inline uint32_t networkToHost32(uint32_t net32) +{ + return be32toh(net32); +} + +inline uint16_t networkToHost16(uint16_t net16) +{ + return be16toh(net16); +} + +#pragma GCC diagnostic pop + +} // namespace sockets +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_ENDIAN_H diff --git a/include/Third_Lib/muduo/net/EventLoop.cc b/include/Third_Lib/muduo/net/EventLoop.cc new file mode 100644 index 0000000..b3feebe --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoop.cc @@ -0,0 +1,278 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoop.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Mutex.h" +#include "muduo/net/Channel.h" +#include "muduo/net/Poller.h" +#include "muduo/net/SocketsOps.h" +#include "muduo/net/TimerQueue.h" + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ +__thread EventLoop* t_loopInThisThread = 0; + +const int kPollTimeMs = 10000; + +int createEventfd() +{ + int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (evtfd < 0) + { + LOG_SYSERR << "Failed in eventfd"; + abort(); + } + return evtfd; +} + +#pragma GCC diagnostic ignored "-Wold-style-cast" +class IgnoreSigPipe +{ + public: + IgnoreSigPipe() + { + ::signal(SIGPIPE, SIG_IGN); + // LOG_TRACE << "Ignore SIGPIPE"; + } +}; +#pragma GCC diagnostic error "-Wold-style-cast" + +IgnoreSigPipe initObj; +} // namespace + +EventLoop* EventLoop::getEventLoopOfCurrentThread() +{ + return t_loopInThisThread; +} + +EventLoop::EventLoop() + : looping_(false), + quit_(false), + eventHandling_(false), + callingPendingFunctors_(false), + iteration_(0), + threadId_(CurrentThread::tid()), + poller_(Poller::newDefaultPoller(this)), + timerQueue_(new TimerQueue(this)), + wakeupFd_(createEventfd()), + wakeupChannel_(new Channel(this, wakeupFd_)), + currentActiveChannel_(NULL) +{ + LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_; + if (t_loopInThisThread) + { + LOG_FATAL << "Another EventLoop " << t_loopInThisThread + << " exists in this thread " << threadId_; + } + else + { + t_loopInThisThread = this; + } + wakeupChannel_->setReadCallback( + std::bind(&EventLoop::handleRead, this)); + // we are always reading the wakeupfd + wakeupChannel_->enableReading(); +} + +EventLoop::~EventLoop() +{ + LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_ + << " destructs in thread " << CurrentThread::tid(); + wakeupChannel_->disableAll(); + wakeupChannel_->remove(); + ::close(wakeupFd_); + t_loopInThisThread = NULL; +} + +void EventLoop::loop() +{ + assert(!looping_); + assertInLoopThread(); + looping_ = true; + quit_ = false; // FIXME: what if someone calls quit() before loop() ? + LOG_TRACE << "EventLoop " << this << " start looping"; + + while (!quit_) + { + activeChannels_.clear(); + pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); + ++iteration_; + if (Logger::logLevel() <= Logger::TRACE) + { + printActiveChannels(); + } + // TODO sort channel by priority + eventHandling_ = true; + for (Channel* channel : activeChannels_) + { + currentActiveChannel_ = channel; + currentActiveChannel_->handleEvent(pollReturnTime_); + } + currentActiveChannel_ = NULL; + eventHandling_ = false; + doPendingFunctors(); + } + + LOG_TRACE << "EventLoop " << this << " stop looping"; + looping_ = false; +} + +void EventLoop::quit() +{ + quit_ = true; + // There is a chance that loop() just executes while(!quit_) and exits, + // then EventLoop destructs, then we are accessing an invalid object. + // Can be fixed using mutex_ in both places. + if (!isInLoopThread()) + { + wakeup(); + } +} + +void EventLoop::runInLoop(Functor cb) +{ + if (isInLoopThread()) + { + cb(); + } + else + { + queueInLoop(std::move(cb)); + } +} + +void EventLoop::queueInLoop(Functor cb) +{ + { + MutexLockGuard lock(mutex_); + pendingFunctors_.push_back(std::move(cb)); + } + + if (!isInLoopThread() || callingPendingFunctors_) + { + wakeup(); + } +} + +size_t EventLoop::queueSize() const +{ + MutexLockGuard lock(mutex_); + return pendingFunctors_.size(); +} + +TimerId EventLoop::runAt(Timestamp time, TimerCallback cb) +{ + return timerQueue_->addTimer(std::move(cb), time, 0.0); +} + +TimerId EventLoop::runAfter(double delay, TimerCallback cb) +{ + Timestamp time(addTime(Timestamp::now(), delay)); + return runAt(time, std::move(cb)); +} + +TimerId EventLoop::runEvery(double interval, TimerCallback cb) +{ + Timestamp time(addTime(Timestamp::now(), interval)); + return timerQueue_->addTimer(std::move(cb), time, interval); +} + +void EventLoop::cancel(TimerId timerId) +{ + return timerQueue_->cancel(timerId); +} + +void EventLoop::updateChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + poller_->updateChannel(channel); +} + +void EventLoop::removeChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + if (eventHandling_) + { + assert(currentActiveChannel_ == channel || + std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end()); + } + poller_->removeChannel(channel); +} + +bool EventLoop::hasChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + return poller_->hasChannel(channel); +} + +void EventLoop::abortNotInLoopThread() +{ + LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this + << " was created in threadId_ = " << threadId_ + << ", current thread id = " << CurrentThread::tid(); +} + +void EventLoop::wakeup() +{ + uint64_t one = 1; + ssize_t n = sockets::write(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8"; + } +} + +void EventLoop::handleRead() +{ + uint64_t one = 1; + ssize_t n = sockets::read(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8"; + } +} + +void EventLoop::doPendingFunctors() +{ + std::vector functors; + callingPendingFunctors_ = true; + + { + MutexLockGuard lock(mutex_); + functors.swap(pendingFunctors_); + } + + for (const Functor& functor : functors) + { + functor(); + } + callingPendingFunctors_ = false; +} + +void EventLoop::printActiveChannels() const +{ + for (const Channel* channel : activeChannels_) + { + LOG_TRACE << "{" << channel->reventsToString() << "} "; + } +} + diff --git a/include/Third_Lib/muduo/net/EventLoop.h b/include/Third_Lib/muduo/net/EventLoop.h new file mode 100644 index 0000000..c2c53d3 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoop.h @@ -0,0 +1,166 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_EVENTLOOP_H +#define MUDUO_NET_EVENTLOOP_H + +#include +#include +#include + +#include + +#include "muduo/base/Mutex.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/TimerId.h" + +namespace muduo +{ +namespace net +{ + +class Channel; +class Poller; +class TimerQueue; + +/// +/// Reactor, at most one per thread. +/// +/// This is an interface class, so don't expose too much details. +class EventLoop : noncopyable +{ + public: + typedef std::function Functor; + + EventLoop(); + ~EventLoop(); // force out-line dtor, for std::unique_ptr members. + + /// + /// Loops forever. + /// + /// Must be called in the same thread as creation of the object. + /// + void loop(); + + /// Quits loop. + /// + /// This is not 100% thread safe, if you call through a raw pointer, + /// better to call through shared_ptr for 100% safety. + void quit(); + + /// + /// Time when poll returns, usually means data arrival. + /// + Timestamp pollReturnTime() const { return pollReturnTime_; } + + int64_t iteration() const { return iteration_; } + + /// Runs callback immediately in the loop thread. + /// It wakes up the loop, and run the cb. + /// If in the same loop thread, cb is run within the function. + /// Safe to call from other threads. + void runInLoop(Functor cb); + /// Queues callback in the loop thread. + /// Runs after finish pooling. + /// Safe to call from other threads. + void queueInLoop(Functor cb); + + size_t queueSize() const; + + // timers + + /// + /// Runs callback at 'time'. + /// Safe to call from other threads. + /// + TimerId runAt(Timestamp time, TimerCallback cb); + /// + /// Runs callback after @c delay seconds. + /// Safe to call from other threads. + /// + TimerId runAfter(double delay, TimerCallback cb); + /// + /// Runs callback every @c interval seconds. + /// Safe to call from other threads. + /// + TimerId runEvery(double interval, TimerCallback cb); + /// + /// Cancels the timer. + /// Safe to call from other threads. + /// + void cancel(TimerId timerId); + + // internal usage + void wakeup(); + void updateChannel(Channel* channel); + void removeChannel(Channel* channel); + bool hasChannel(Channel* channel); + + // pid_t threadId() const { return threadId_; } + void assertInLoopThread() + { + if (!isInLoopThread()) + { + abortNotInLoopThread(); + } + } + bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } + // bool callingPendingFunctors() const { return callingPendingFunctors_; } + bool eventHandling() const { return eventHandling_; } + + void setContext(const boost::any& context) + { context_ = context; } + + const boost::any& getContext() const + { return context_; } + + boost::any* getMutableContext() + { return &context_; } + + static EventLoop* getEventLoopOfCurrentThread(); + + private: + void abortNotInLoopThread(); + void handleRead(); // waked up + void doPendingFunctors(); + + void printActiveChannels() const; // DEBUG + + typedef std::vector ChannelList; + + bool looping_; /* atomic */ + std::atomic quit_; + bool eventHandling_; /* atomic */ + bool callingPendingFunctors_; /* atomic */ + int64_t iteration_; + const pid_t threadId_; + Timestamp pollReturnTime_; + std::unique_ptr poller_; + std::unique_ptr timerQueue_; + int wakeupFd_; + // unlike in TimerQueue, which is an internal class, + // we don't expose Channel to client. + std::unique_ptr wakeupChannel_; + boost::any context_; + + // scratch variables + ChannelList activeChannels_; + Channel* currentActiveChannel_; + + mutable MutexLock mutex_; + std::vector pendingFunctors_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOP_H diff --git a/include/Third_Lib/muduo/net/EventLoopThread.cc b/include/Third_Lib/muduo/net/EventLoopThread.cc new file mode 100644 index 0000000..c1b6fa5 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThread.cc @@ -0,0 +1,77 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoopThread.h" + +#include "muduo/net/EventLoop.h" + +using namespace muduo; +using namespace muduo::net; + +EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, + const string& name) + : loop_(NULL), + exiting_(false), + thread_(std::bind(&EventLoopThread::threadFunc, this), name), + mutex_(), + cond_(mutex_), + callback_(cb) +{ +} + +EventLoopThread::~EventLoopThread() +{ + exiting_ = true; + if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_. + { + // still a tiny chance to call destructed object, if threadFunc exits just now. + // but when EventLoopThread destructs, usually programming is exiting anyway. + loop_->quit(); + thread_.join(); + } +} + +EventLoop* EventLoopThread::startLoop() +{ + assert(!thread_.started()); + thread_.start(); + + EventLoop* loop = NULL; + { + MutexLockGuard lock(mutex_); + while (loop_ == NULL) + { + cond_.wait(); + } + loop = loop_; + } + + return loop; +} + +void EventLoopThread::threadFunc() +{ + EventLoop loop; + + if (callback_) + { + callback_(&loop); + } + + { + MutexLockGuard lock(mutex_); + loop_ = &loop; + cond_.notify(); + } + + loop.loop(); + //assert(exiting_); + MutexLockGuard lock(mutex_); + loop_ = NULL; +} + diff --git a/include/Third_Lib/muduo/net/EventLoopThread.h b/include/Third_Lib/muduo/net/EventLoopThread.h new file mode 100644 index 0000000..7e839d7 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThread.h @@ -0,0 +1,50 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_EVENTLOOPTHREAD_H +#define MUDUO_NET_EVENTLOOPTHREAD_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; + +class EventLoopThread : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + + EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(), + const string& name = string()); + ~EventLoopThread(); + EventLoop* startLoop(); + + private: + void threadFunc(); + + EventLoop* loop_ GUARDED_BY(mutex_); + bool exiting_; + Thread thread_; + MutexLock mutex_; + Condition cond_ GUARDED_BY(mutex_); + ThreadInitCallback callback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOPTHREAD_H + diff --git a/include/Third_Lib/muduo/net/EventLoopThreadPool.cc b/include/Third_Lib/muduo/net/EventLoopThreadPool.cc new file mode 100644 index 0000000..1ee5949 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThreadPool.cc @@ -0,0 +1,97 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoopThreadPool.h" + +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg) + : baseLoop_(baseLoop), + name_(nameArg), + started_(false), + numThreads_(0), + next_(0) +{ +} + +EventLoopThreadPool::~EventLoopThreadPool() +{ + // Don't delete loop, it's stack variable +} + +void EventLoopThreadPool::start(const ThreadInitCallback& cb) +{ + assert(!started_); + baseLoop_->assertInLoopThread(); + + started_ = true; + + for (int i = 0; i < numThreads_; ++i) + { + char buf[name_.size() + 32]; + snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i); + EventLoopThread* t = new EventLoopThread(cb, buf); + threads_.push_back(std::unique_ptr(t)); + loops_.push_back(t->startLoop()); + } + if (numThreads_ == 0 && cb) + { + cb(baseLoop_); + } +} + +EventLoop* EventLoopThreadPool::getNextLoop() +{ + baseLoop_->assertInLoopThread(); + assert(started_); + EventLoop* loop = baseLoop_; + + if (!loops_.empty()) + { + // round-robin + loop = loops_[next_]; + ++next_; + if (implicit_cast(next_) >= loops_.size()) + { + next_ = 0; + } + } + return loop; +} + +EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode) +{ + baseLoop_->assertInLoopThread(); + EventLoop* loop = baseLoop_; + + if (!loops_.empty()) + { + loop = loops_[hashCode % loops_.size()]; + } + return loop; +} + +std::vector EventLoopThreadPool::getAllLoops() +{ + baseLoop_->assertInLoopThread(); + assert(started_); + if (loops_.empty()) + { + return std::vector(1, baseLoop_); + } + else + { + return loops_; + } +} diff --git a/include/Third_Lib/muduo/net/EventLoopThreadPool.h b/include/Third_Lib/muduo/net/EventLoopThreadPool.h new file mode 100644 index 0000000..7389148 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThreadPool.h @@ -0,0 +1,69 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H +#define MUDUO_NET_EVENTLOOPTHREADPOOL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ + +namespace net +{ + +class EventLoop; +class EventLoopThread; + +class EventLoopThreadPool : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + + EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg); + ~EventLoopThreadPool(); + void setThreadNum(int numThreads) { numThreads_ = numThreads; } + void start(const ThreadInitCallback& cb = ThreadInitCallback()); + + // valid after calling start() + /// round-robin + EventLoop* getNextLoop(); + + /// with the same hash code, it will always return the same EventLoop + EventLoop* getLoopForHash(size_t hashCode); + + std::vector getAllLoops(); + + bool started() const + { return started_; } + + const string& name() const + { return name_; } + + private: + + EventLoop* baseLoop_; + string name_; + bool started_; + int numThreads_; + int next_; + std::vector> threads_; + std::vector loops_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H diff --git a/include/Third_Lib/muduo/net/InetAddress.cc b/include/Third_Lib/muduo/net/InetAddress.cc new file mode 100644 index 0000000..7c5e0ae --- /dev/null +++ b/include/Third_Lib/muduo/net/InetAddress.cc @@ -0,0 +1,149 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/InetAddress.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/SocketsOps.h" + +#include +#include + +// INADDR_ANY use (type)value casting. +#pragma GCC diagnostic ignored "-Wold-style-cast" +static const in_addr_t kInaddrAny = INADDR_ANY; +static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; +#pragma GCC diagnostic error "-Wold-style-cast" + +// /* Structure describing an Internet socket address. */ +// struct sockaddr_in { +// sa_family_t sin_family; /* address family: AF_INET */ +// uint16_t sin_port; /* port in network byte order */ +// struct in_addr sin_addr; /* internet address */ +// }; + +// /* Internet address. */ +// typedef uint32_t in_addr_t; +// struct in_addr { +// in_addr_t s_addr; /* address in network byte order */ +// }; + +// struct sockaddr_in6 { +// sa_family_t sin6_family; /* address family: AF_INET6 */ +// uint16_t sin6_port; /* port in network byte order */ +// uint32_t sin6_flowinfo; /* IPv6 flow information */ +// struct in6_addr sin6_addr; /* IPv6 address */ +// uint32_t sin6_scope_id; /* IPv6 scope-id */ +// }; + +using namespace muduo; +using namespace muduo::net; + +static_assert(sizeof(InetAddress) == sizeof(struct sockaddr_in6), + "InetAddress is same size as sockaddr_in6"); +static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0"); +static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0"); +static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2"); +static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2"); + +InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) +{ + static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0"); + static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0"); + if (ipv6) + { + memZero(&addr6_, sizeof addr6_); + addr6_.sin6_family = AF_INET6; + in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; + addr6_.sin6_addr = ip; + addr6_.sin6_port = sockets::hostToNetwork16(port); + } + else + { + memZero(&addr_, sizeof addr_); + addr_.sin_family = AF_INET; + in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; + addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip); + addr_.sin_port = sockets::hostToNetwork16(port); + } +} + +InetAddress::InetAddress(StringArg ip, uint16_t port, bool ipv6) +{ + if (ipv6 || strchr(ip.c_str(), ':')) + { + memZero(&addr6_, sizeof addr6_); + sockets::fromIpPort(ip.c_str(), port, &addr6_); + } + else + { + memZero(&addr_, sizeof addr_); + sockets::fromIpPort(ip.c_str(), port, &addr_); + } +} + +string InetAddress::toIpPort() const +{ + char buf[64] = ""; + sockets::toIpPort(buf, sizeof buf, getSockAddr()); + return buf; +} + +string InetAddress::toIp() const +{ + char buf[64] = ""; + sockets::toIp(buf, sizeof buf, getSockAddr()); + return buf; +} + +uint32_t InetAddress::ipv4NetEndian() const +{ + assert(family() == AF_INET); + return addr_.sin_addr.s_addr; +} + +uint16_t InetAddress::port() const +{ + return sockets::networkToHost16(portNetEndian()); +} + +static __thread char t_resolveBuffer[64 * 1024]; + +bool InetAddress::resolve(StringArg hostname, InetAddress* out) +{ + assert(out != NULL); + struct hostent hent; + struct hostent* he = NULL; + int herrno = 0; + memZero(&hent, sizeof(hent)); + + int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); + if (ret == 0 && he != NULL) + { + assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); + out->addr_.sin_addr = *reinterpret_cast(he->h_addr); + return true; + } + else + { + if (ret) + { + LOG_SYSERR << "InetAddress::resolve"; + } + return false; + } +} + +void InetAddress::setScopeId(uint32_t scope_id) +{ + if (family() == AF_INET6) + { + addr6_.sin6_scope_id = scope_id; + } +} diff --git a/include/Third_Lib/muduo/net/InetAddress.h b/include/Third_Lib/muduo/net/InetAddress.h new file mode 100644 index 0000000..c5263a7 --- /dev/null +++ b/include/Third_Lib/muduo/net/InetAddress.h @@ -0,0 +1,86 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_INETADDRESS_H +#define MUDUO_NET_INETADDRESS_H + +#include "muduo/base/copyable.h" +#include "muduo/base/StringPiece.h" + +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ +const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); +} + +/// +/// Wrapper of sockaddr_in. +/// +/// This is an POD interface class. +class InetAddress : public muduo::copyable +{ + public: + /// Constructs an endpoint with given port number. + /// Mostly used in TcpServer listening. + explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); + + /// Constructs an endpoint with given ip and port. + /// @c ip should be "1.2.3.4" + InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); + + /// Constructs an endpoint with given struct @c sockaddr_in + /// Mostly used when accepting new connections + explicit InetAddress(const struct sockaddr_in& addr) + : addr_(addr) + { } + + explicit InetAddress(const struct sockaddr_in6& addr) + : addr6_(addr) + { } + + sa_family_t family() const { return addr_.sin_family; } + string toIp() const; + string toIpPort() const; + uint16_t port() const; + + // default copy/assignment are Okay + + const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); } + void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; } + + uint32_t ipv4NetEndian() const; + uint16_t portNetEndian() const { return addr_.sin_port; } + + // resolve hostname to IP address, not changing port or sin_family + // return true on success. + // thread safe + static bool resolve(StringArg hostname, InetAddress* result); + // static std::vector resolveAll(const char* hostname, uint16_t port = 0); + + // set IPv6 ScopeID + void setScopeId(uint32_t scope_id); + + private: + union + { + struct sockaddr_in addr_; + struct sockaddr_in6 addr6_; + }; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INETADDRESS_H diff --git a/include/Third_Lib/muduo/net/Poller.cc b/include/Third_Lib/muduo/net/Poller.cc new file mode 100644 index 0000000..cfe4c3c --- /dev/null +++ b/include/Third_Lib/muduo/net/Poller.cc @@ -0,0 +1,29 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Poller.h" + +#include "muduo/net/Channel.h" + +using namespace muduo; +using namespace muduo::net; + +Poller::Poller(EventLoop* loop) + : ownerLoop_(loop) +{ +} + +Poller::~Poller() = default; + +bool Poller::hasChannel(Channel* channel) const +{ + assertInLoopThread(); + ChannelMap::const_iterator it = channels_.find(channel->fd()); + return it != channels_.end() && it->second == channel; +} + diff --git a/include/Third_Lib/muduo/net/Poller.h b/include/Third_Lib/muduo/net/Poller.h new file mode 100644 index 0000000..089e60b --- /dev/null +++ b/include/Third_Lib/muduo/net/Poller.h @@ -0,0 +1,71 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_H +#define MUDUO_NET_POLLER_H + +#include +#include + +#include "muduo/base/Timestamp.h" +#include "muduo/net/EventLoop.h" + +namespace muduo +{ +namespace net +{ + +class Channel; + +/// +/// Base class for IO Multiplexing +/// +/// This class doesn't own the Channel objects. +class Poller : noncopyable +{ + public: + typedef std::vector ChannelList; + + Poller(EventLoop* loop); + virtual ~Poller(); + + /// Polls the I/O events. + /// Must be called in the loop thread. + virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; + + /// Changes the interested I/O events. + /// Must be called in the loop thread. + virtual void updateChannel(Channel* channel) = 0; + + /// Remove the channel, when it destructs. + /// Must be called in the loop thread. + virtual void removeChannel(Channel* channel) = 0; + + virtual bool hasChannel(Channel* channel) const; + + static Poller* newDefaultPoller(EventLoop* loop); + + void assertInLoopThread() const + { + ownerLoop_->assertInLoopThread(); + } + + protected: + typedef std::map ChannelMap; + ChannelMap channels_; + + private: + EventLoop* ownerLoop_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_POLLER_H diff --git a/include/Third_Lib/muduo/net/Socket.cc b/include/Third_Lib/muduo/net/Socket.cc new file mode 100644 index 0000000..fc13147 --- /dev/null +++ b/include/Third_Lib/muduo/net/Socket.cc @@ -0,0 +1,128 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Socket.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/SocketsOps.h" + +#include +#include +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +Socket::~Socket() +{ + sockets::close(sockfd_); +} + +bool Socket::getTcpInfo(struct tcp_info* tcpi) const +{ + socklen_t len = sizeof(*tcpi); + memZero(tcpi, len); + return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; +} + +bool Socket::getTcpInfoString(char* buf, int len) const +{ + struct tcp_info tcpi; + bool ok = getTcpInfo(&tcpi); + if (ok) + { + snprintf(buf, len, "unrecovered=%u " + "rto=%u ato=%u snd_mss=%u rcv_mss=%u " + "lost=%u retrans=%u rtt=%u rttvar=%u " + "sshthresh=%u cwnd=%u total_retrans=%u", + tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts + tcpi.tcpi_rto, // Retransmit timeout in usec + tcpi.tcpi_ato, // Predicted tick of soft clock in usec + tcpi.tcpi_snd_mss, + tcpi.tcpi_rcv_mss, + tcpi.tcpi_lost, // Lost packets + tcpi.tcpi_retrans, // Retransmitted packets out + tcpi.tcpi_rtt, // Smoothed round trip time in usec + tcpi.tcpi_rttvar, // Medium deviation + tcpi.tcpi_snd_ssthresh, + tcpi.tcpi_snd_cwnd, + tcpi.tcpi_total_retrans); // Total retransmits for entire connection + } + return ok; +} + +void Socket::bindAddress(const InetAddress& addr) +{ + sockets::bindOrDie(sockfd_, addr.getSockAddr()); +} + +void Socket::listen() +{ + sockets::listenOrDie(sockfd_); +} + +int Socket::accept(InetAddress* peeraddr) +{ + struct sockaddr_in6 addr; + memZero(&addr, sizeof addr); + int connfd = sockets::accept(sockfd_, &addr); + if (connfd >= 0) + { + peeraddr->setSockAddrInet6(addr); + } + return connfd; +} + +void Socket::shutdownWrite() +{ + sockets::shutdownWrite(sockfd_); +} + +void Socket::setTcpNoDelay(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + +void Socket::setReuseAddr(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + +void Socket::setReusePort(bool on) +{ +#ifdef SO_REUSEPORT + int optval = on ? 1 : 0; + int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, + &optval, static_cast(sizeof optval)); + if (ret < 0 && on) + { + LOG_SYSERR << "SO_REUSEPORT failed."; + } +#else + if (on) + { + LOG_ERROR << "SO_REUSEPORT is not supported."; + } +#endif +} + +void Socket::setKeepAlive(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + diff --git a/include/Third_Lib/muduo/net/Socket.h b/include/Third_Lib/muduo/net/Socket.h new file mode 100644 index 0000000..17567be --- /dev/null +++ b/include/Third_Lib/muduo/net/Socket.h @@ -0,0 +1,89 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_SOCKET_H +#define MUDUO_NET_SOCKET_H + +#include "muduo/base/noncopyable.h" + +// struct tcp_info is in +struct tcp_info; + +namespace muduo +{ +/// +/// TCP networking. +/// +namespace net +{ + +class InetAddress; + +/// +/// Wrapper of socket file descriptor. +/// +/// It closes the sockfd when desctructs. +/// It's thread safe, all operations are delagated to OS. +class Socket : noncopyable +{ + public: + explicit Socket(int sockfd) + : sockfd_(sockfd) + { } + + // Socket(Socket&&) // move constructor in C++11 + ~Socket(); + + int fd() const { return sockfd_; } + // return true if success. + bool getTcpInfo(struct tcp_info*) const; + bool getTcpInfoString(char* buf, int len) const; + + /// abort if address in use + void bindAddress(const InetAddress& localaddr); + /// abort if address in use + void listen(); + + /// On success, returns a non-negative integer that is + /// a descriptor for the accepted socket, which has been + /// set to non-blocking and close-on-exec. *peeraddr is assigned. + /// On error, -1 is returned, and *peeraddr is untouched. + int accept(InetAddress* peeraddr); + + void shutdownWrite(); + + /// + /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). + /// + void setTcpNoDelay(bool on); + + /// + /// Enable/disable SO_REUSEADDR + /// + void setReuseAddr(bool on); + + /// + /// Enable/disable SO_REUSEPORT + /// + void setReusePort(bool on); + + /// + /// Enable/disable SO_KEEPALIVE + /// + void setKeepAlive(bool on); + + private: + const int sockfd_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_SOCKET_H diff --git a/include/Third_Lib/muduo/net/SocketsOps.cc b/include/Third_Lib/muduo/net/SocketsOps.cc new file mode 100644 index 0000000..465c507 --- /dev/null +++ b/include/Third_Lib/muduo/net/SocketsOps.cc @@ -0,0 +1,316 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/SocketsOps.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Types.h" +#include "muduo/net/Endian.h" + +#include +#include +#include // snprintf +#include +#include // readv +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + +typedef struct sockaddr SA; + + +#if VALGRIND || defined (NO_ACCEPT4) +void setNonBlockAndCloseOnExec(int sockfd) +{ + // non-block + int flags = ::fcntl(sockfd, F_GETFL, 0); + flags |= O_NONBLOCK; + int ret = ::fcntl(sockfd, F_SETFL, flags); + // FIXME check + + // close-on-exec + flags = ::fcntl(sockfd, F_GETFD, 0); + flags |= FD_CLOEXEC; + ret = ::fcntl(sockfd, F_SETFD, flags); + // FIXME check + + (void)ret; +} +#endif + +} // namespace + +const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in6* addr) +{ + return static_cast(implicit_cast(addr)); +} + +struct sockaddr* sockets::sockaddr_cast(struct sockaddr_in6* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr_in* sockets::sockaddr_in_cast(const struct sockaddr* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr_in6* sockets::sockaddr_in6_cast(const struct sockaddr* addr) +{ + return static_cast(implicit_cast(addr)); +} + +int sockets::createNonblockingOrDie(sa_family_t family) +{ +#if VALGRIND + int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP); + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } + + setNonBlockAndCloseOnExec(sockfd); +#else + int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } +#endif + return sockfd; +} + +void sockets::bindOrDie(int sockfd, const struct sockaddr* addr) +{ + int ret = ::bind(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); + if (ret < 0) + { + LOG_SYSFATAL << "sockets::bindOrDie"; + } +} + +void sockets::listenOrDie(int sockfd) +{ + int ret = ::listen(sockfd, SOMAXCONN); + if (ret < 0) + { + LOG_SYSFATAL << "sockets::listenOrDie"; + } +} + +int sockets::accept(int sockfd, struct sockaddr_in6* addr) +{ + socklen_t addrlen = static_cast(sizeof *addr); +#if VALGRIND || defined (NO_ACCEPT4) + int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); + setNonBlockAndCloseOnExec(connfd); +#else + int connfd = ::accept4(sockfd, sockaddr_cast(addr), + &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); +#endif + if (connfd < 0) + { + int savedErrno = errno; + LOG_SYSERR << "Socket::accept"; + switch (savedErrno) + { + case EAGAIN: + case ECONNABORTED: + case EINTR: + case EPROTO: // ??? + case EPERM: + case EMFILE: // per-process lmit of open file desctiptor ??? + // expected errors + errno = savedErrno; + break; + case EBADF: + case EFAULT: + case EINVAL: + case ENFILE: + case ENOBUFS: + case ENOMEM: + case ENOTSOCK: + case EOPNOTSUPP: + // unexpected errors + LOG_FATAL << "unexpected error of ::accept " << savedErrno; + break; + default: + LOG_FATAL << "unknown error of ::accept " << savedErrno; + break; + } + } + return connfd; +} + +int sockets::connect(int sockfd, const struct sockaddr* addr) +{ + return ::connect(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); +} + +ssize_t sockets::read(int sockfd, void *buf, size_t count) +{ + return ::read(sockfd, buf, count); +} + +ssize_t sockets::readv(int sockfd, const struct iovec *iov, int iovcnt) +{ + return ::readv(sockfd, iov, iovcnt); +} + +ssize_t sockets::write(int sockfd, const void *buf, size_t count) +{ + return ::write(sockfd, buf, count); +} + +void sockets::close(int sockfd) +{ + if (::close(sockfd) < 0) + { + LOG_SYSERR << "sockets::close"; + } +} + +void sockets::shutdownWrite(int sockfd) +{ + if (::shutdown(sockfd, SHUT_WR) < 0) + { + LOG_SYSERR << "sockets::shutdownWrite"; + } +} + +void sockets::toIpPort(char* buf, size_t size, + const struct sockaddr* addr) +{ + if (addr->sa_family == AF_INET6) + { + buf[0] = '['; + toIp(buf+1, size-1, addr); + size_t end = ::strlen(buf); + const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); + uint16_t port = sockets::networkToHost16(addr6->sin6_port); + assert(size > end); + snprintf(buf+end, size-end, "]:%u", port); + return; + } + toIp(buf, size, addr); + size_t end = ::strlen(buf); + const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); + uint16_t port = sockets::networkToHost16(addr4->sin_port); + assert(size > end); + snprintf(buf+end, size-end, ":%u", port); +} + +void sockets::toIp(char* buf, size_t size, + const struct sockaddr* addr) +{ + if (addr->sa_family == AF_INET) + { + assert(size >= INET_ADDRSTRLEN); + const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); + ::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast(size)); + } + else if (addr->sa_family == AF_INET6) + { + assert(size >= INET6_ADDRSTRLEN); + const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); + ::inet_ntop(AF_INET6, &addr6->sin6_addr, buf, static_cast(size)); + } +} + +void sockets::fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in* addr) +{ + addr->sin_family = AF_INET; + addr->sin_port = hostToNetwork16(port); + if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) + { + LOG_SYSERR << "sockets::fromIpPort"; + } +} + +void sockets::fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in6* addr) +{ + addr->sin6_family = AF_INET6; + addr->sin6_port = hostToNetwork16(port); + if (::inet_pton(AF_INET6, ip, &addr->sin6_addr) <= 0) + { + LOG_SYSERR << "sockets::fromIpPort"; + } +} + +int sockets::getSocketError(int sockfd) +{ + int optval; + socklen_t optlen = static_cast(sizeof optval); + + if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) + { + return errno; + } + else + { + return optval; + } +} + +struct sockaddr_in6 sockets::getLocalAddr(int sockfd) +{ + struct sockaddr_in6 localaddr; + memZero(&localaddr, sizeof localaddr); + socklen_t addrlen = static_cast(sizeof localaddr); + if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getLocalAddr"; + } + return localaddr; +} + +struct sockaddr_in6 sockets::getPeerAddr(int sockfd) +{ + struct sockaddr_in6 peeraddr; + memZero(&peeraddr, sizeof peeraddr); + socklen_t addrlen = static_cast(sizeof peeraddr); + if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getPeerAddr"; + } + return peeraddr; +} + +bool sockets::isSelfConnect(int sockfd) +{ + struct sockaddr_in6 localaddr = getLocalAddr(sockfd); + struct sockaddr_in6 peeraddr = getPeerAddr(sockfd); + if (localaddr.sin6_family == AF_INET) + { + const struct sockaddr_in* laddr4 = reinterpret_cast(&localaddr); + const struct sockaddr_in* raddr4 = reinterpret_cast(&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) + { + return localaddr.sin6_port == peeraddr.sin6_port + && memcmp(&localaddr.sin6_addr, &peeraddr.sin6_addr, sizeof localaddr.sin6_addr) == 0; + } + else + { + return false; + } +} + diff --git a/include/Third_Lib/muduo/net/SocketsOps.h b/include/Third_Lib/muduo/net/SocketsOps.h new file mode 100644 index 0000000..9c46597 --- /dev/null +++ b/include/Third_Lib/muduo/net/SocketsOps.h @@ -0,0 +1,64 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_SOCKETSOPS_H +#define MUDUO_NET_SOCKETSOPS_H + +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ + +/// +/// Creates a non-blocking socket file descriptor, +/// abort if any error. +int createNonblockingOrDie(sa_family_t family); + +int connect(int sockfd, const struct sockaddr* addr); +void bindOrDie(int sockfd, const struct sockaddr* addr); +void listenOrDie(int sockfd); +int accept(int sockfd, struct sockaddr_in6* addr); +ssize_t read(int sockfd, void *buf, size_t count); +ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); +ssize_t write(int sockfd, const void *buf, size_t count); +void close(int sockfd); +void shutdownWrite(int sockfd); + +void toIpPort(char* buf, size_t size, + const struct sockaddr* addr); +void toIp(char* buf, size_t size, + const struct sockaddr* addr); + +void fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in* addr); +void fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in6* addr); + +int getSocketError(int sockfd); + +const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); +const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); +struct sockaddr* sockaddr_cast(struct sockaddr_in6* addr); +const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); +const struct sockaddr_in6* sockaddr_in6_cast(const struct sockaddr* addr); + +struct sockaddr_in6 getLocalAddr(int sockfd); +struct sockaddr_in6 getPeerAddr(int sockfd); +bool isSelfConnect(int sockfd); + +} // namespace sockets +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_SOCKETSOPS_H diff --git a/include/Third_Lib/muduo/net/TcpClient.cc b/include/Third_Lib/muduo/net/TcpClient.cc new file mode 100644 index 0000000..1e668b3 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpClient.cc @@ -0,0 +1,181 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/TcpClient.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Connector.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/SocketsOps.h" + +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +// TcpClient::TcpClient(EventLoop* loop) +// : loop_(loop) +// { +// } + +// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) +// : loop_(CHECK_NOTNULL(loop)), +// serverAddr_(host, port) +// { +// } + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn) +{ + loop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); +} + +void removeConnector(const ConnectorPtr& connector) +{ + //connector-> +} + +} // namespace detail +} // namespace net +} // namespace muduo + +TcpClient::TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& nameArg) + : loop_(CHECK_NOTNULL(loop)), + connector_(new Connector(loop, serverAddr)), + name_(nameArg), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), + retry_(false), + connect_(true), + nextConnId_(1) +{ + connector_->setNewConnectionCallback( + std::bind(&TcpClient::newConnection, this, _1)); + // FIXME setConnectFailedCallback + LOG_INFO << "TcpClient::TcpClient[" << name_ + << "] - connector " << get_pointer(connector_); +} + +TcpClient::~TcpClient() +{ + LOG_INFO << "TcpClient::~TcpClient[" << name_ + << "] - connector " << get_pointer(connector_); + TcpConnectionPtr conn; + bool unique = false; + { + MutexLockGuard lock(mutex_); + unique = connection_.unique(); + conn = connection_; + } + if (conn) + { + assert(loop_ == conn->getLoop()); + // FIXME: not 100% safe, if we are in different thread + CloseCallback cb = std::bind(&detail::removeConnection, loop_, _1); + loop_->runInLoop( + std::bind(&TcpConnection::setCloseCallback, conn, cb)); + if (unique) + { + conn->forceClose(); + } + } + else + { + connector_->stop(); + // FIXME: HACK + loop_->runAfter(1, std::bind(&detail::removeConnector, connector_)); + } +} + +void TcpClient::connect() +{ + // FIXME: check state + LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to " + << connector_->serverAddress().toIpPort(); + connect_ = true; + connector_->start(); +} + +void TcpClient::disconnect() +{ + connect_ = false; + + { + MutexLockGuard lock(mutex_); + if (connection_) + { + connection_->shutdown(); + } + } +} + +void TcpClient::stop() +{ + connect_ = false; + connector_->stop(); +} + +void TcpClient::newConnection(int sockfd) +{ + loop_->assertInLoopThread(); + InetAddress peerAddr(sockets::getPeerAddr(sockfd)); + char buf[32]; + snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toIpPort().c_str(), nextConnId_); + ++nextConnId_; + string connName = name_ + buf; + + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection + // FIXME use make_shared if necessary + TcpConnectionPtr conn(new TcpConnection(loop_, + connName, + sockfd, + localAddr, + peerAddr)); + + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); + conn->setCloseCallback( + std::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe + { + MutexLockGuard lock(mutex_); + connection_ = conn; + } + conn->connectEstablished(); +} + +void TcpClient::removeConnection(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + assert(loop_ == conn->getLoop()); + + { + MutexLockGuard lock(mutex_); + assert(connection_ == conn); + connection_.reset(); + } + + loop_->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); + if (retry_ && connect_) + { + LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to " + << connector_->serverAddress().toIpPort(); + connector_->restart(); + } +} + diff --git a/include/Third_Lib/muduo/net/TcpClient.h b/include/Third_Lib/muduo/net/TcpClient.h new file mode 100644 index 0000000..c498cb3 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpClient.h @@ -0,0 +1,90 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPCLIENT_H +#define MUDUO_NET_TCPCLIENT_H + +#include "muduo/base/Mutex.h" +#include "muduo/net/TcpConnection.h" + +namespace muduo +{ +namespace net +{ + +class Connector; +typedef std::shared_ptr ConnectorPtr; + +class TcpClient : noncopyable +{ + public: + // TcpClient(EventLoop* loop); + // TcpClient(EventLoop* loop, const string& host, uint16_t port); + TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& nameArg); + ~TcpClient(); // force out-line dtor, for std::unique_ptr members. + + void connect(); + void disconnect(); + void stop(); + + TcpConnectionPtr connection() const + { + MutexLockGuard lock(mutex_); + return connection_; + } + + EventLoop* getLoop() const { return loop_; } + bool retry() const { return retry_; } + void enableRetry() { retry_ = true; } + + const string& name() const + { return name_; } + + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(ConnectionCallback cb) + { connectionCallback_ = std::move(cb); } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(MessageCallback cb) + { messageCallback_ = std::move(cb); } + + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(WriteCompleteCallback cb) + { writeCompleteCallback_ = std::move(cb); } + + private: + /// Not thread safe, but in loop + void newConnection(int sockfd); + /// Not thread safe, but in loop + void removeConnection(const TcpConnectionPtr& conn); + + EventLoop* loop_; + ConnectorPtr connector_; // avoid revealing Connector + const string name_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + bool retry_; // atomic + bool connect_; // atomic + // always in loop thread + int nextConnId_; + mutable MutexLock mutex_; + TcpConnectionPtr connection_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPCLIENT_H diff --git a/include/Third_Lib/muduo/net/TcpConnection.cc b/include/Third_Lib/muduo/net/TcpConnection.cc new file mode 100644 index 0000000..37f58a4 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpConnection.cc @@ -0,0 +1,429 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/TcpConnection.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/WeakCallback.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/Socket.h" +#include "muduo/net/SocketsOps.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn) +{ + LOG_TRACE << conn->localAddress().toIpPort() << " -> " + << conn->peerAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + // do not call conn->forceClose(), because some users want to register message callback only. +} + +void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, + Buffer* buf, + Timestamp) +{ + buf->retrieveAll(); +} + +TcpConnection::TcpConnection(EventLoop* loop, + const string& nameArg, + int sockfd, + const InetAddress& localAddr, + const InetAddress& peerAddr) + : loop_(CHECK_NOTNULL(loop)), + name_(nameArg), + state_(kConnecting), + reading_(true), + socket_(new Socket(sockfd)), + channel_(new Channel(loop, sockfd)), + localAddr_(localAddr), + peerAddr_(peerAddr), + highWaterMark_(64*1024*1024) +{ + channel_->setReadCallback( + std::bind(&TcpConnection::handleRead, this, _1)); + channel_->setWriteCallback( + std::bind(&TcpConnection::handleWrite, this)); + channel_->setCloseCallback( + std::bind(&TcpConnection::handleClose, this)); + channel_->setErrorCallback( + std::bind(&TcpConnection::handleError, this)); + LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this + << " fd=" << sockfd; + socket_->setKeepAlive(true); +} + +TcpConnection::~TcpConnection() +{ + LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this + << " fd=" << channel_->fd() + << " state=" << stateToString(); + assert(state_ == kDisconnected); +} + +bool TcpConnection::getTcpInfo(struct tcp_info* tcpi) const +{ + return socket_->getTcpInfo(tcpi); +} + +string TcpConnection::getTcpInfoString() const +{ + char buf[1024]; + buf[0] = '\0'; + socket_->getTcpInfoString(buf, sizeof buf); + return buf; +} + +void TcpConnection::send(const void* data, int len) +{ + send(StringPiece(static_cast(data), len)); +} + +void TcpConnection::send(const StringPiece& message) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(message); + } + else + { + void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; + loop_->runInLoop( + std::bind(fp, + this, // FIXME + message.as_string())); + //std::forward(message))); + } + } +} + +// FIXME efficiency!!! +void TcpConnection::send(Buffer* buf) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(buf->peek(), buf->readableBytes()); + buf->retrieveAll(); + } + else + { + void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; + loop_->runInLoop( + std::bind(fp, + this, // FIXME + buf->retrieveAllAsString())); + //std::forward(message))); + } + } +} + +void TcpConnection::sendInLoop(const StringPiece& message) +{ + sendInLoop(message.data(), message.size()); +} + +void TcpConnection::sendInLoop(const void* data, size_t len) +{ + loop_->assertInLoopThread(); + ssize_t nwrote = 0; + size_t remaining = len; + bool faultError = false; + if (state_ == kDisconnected) + { + LOG_WARN << "disconnected, give up writing"; + return; + } + // if no thing in output queue, try writing directly + if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) + { + nwrote = sockets::write(channel_->fd(), data, len); + if (nwrote >= 0) + { + remaining = len - nwrote; + if (remaining == 0 && writeCompleteCallback_) + { + loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); + } + } + else // nwrote < 0 + { + nwrote = 0; + if (errno != EWOULDBLOCK) + { + LOG_SYSERR << "TcpConnection::sendInLoop"; + if (errno == EPIPE || errno == ECONNRESET) // FIXME: any others? + { + faultError = true; + } + } + } + } + + assert(remaining <= len); + if (!faultError && remaining > 0) + { + size_t oldLen = outputBuffer_.readableBytes(); + if (oldLen + remaining >= highWaterMark_ + && oldLen < highWaterMark_ + && highWaterMarkCallback_) + { + loop_->queueInLoop(std::bind(highWaterMarkCallback_, shared_from_this(), oldLen + remaining)); + } + outputBuffer_.append(static_cast(data)+nwrote, remaining); + if (!channel_->isWriting()) + { + channel_->enableWriting(); + } + } +} + +void TcpConnection::shutdown() +{ + // FIXME: use compare and swap + if (state_ == kConnected) + { + setState(kDisconnecting); + // FIXME: shared_from_this()? + loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this)); + } +} + +void TcpConnection::shutdownInLoop() +{ + loop_->assertInLoopThread(); + if (!channel_->isWriting()) + { + // we are not writing + socket_->shutdownWrite(); + } +} + +// void TcpConnection::shutdownAndForceCloseAfter(double seconds) +// { +// // FIXME: use compare and swap +// if (state_ == kConnected) +// { +// setState(kDisconnecting); +// loop_->runInLoop(std::bind(&TcpConnection::shutdownAndForceCloseInLoop, this, seconds)); +// } +// } + +// void TcpConnection::shutdownAndForceCloseInLoop(double seconds) +// { +// loop_->assertInLoopThread(); +// if (!channel_->isWriting()) +// { +// // we are not writing +// socket_->shutdownWrite(); +// } +// loop_->runAfter( +// seconds, +// makeWeakCallback(shared_from_this(), +// &TcpConnection::forceCloseInLoop)); +// } + +void TcpConnection::forceClose() +{ + // FIXME: use compare and swap + if (state_ == kConnected || state_ == kDisconnecting) + { + setState(kDisconnecting); + loop_->queueInLoop(std::bind(&TcpConnection::forceCloseInLoop, shared_from_this())); + } +} + +void TcpConnection::forceCloseWithDelay(double seconds) +{ + if (state_ == kConnected || state_ == kDisconnecting) + { + setState(kDisconnecting); + loop_->runAfter( + seconds, + makeWeakCallback(shared_from_this(), + &TcpConnection::forceClose)); // not forceCloseInLoop to avoid race condition + } +} + +void TcpConnection::forceCloseInLoop() +{ + loop_->assertInLoopThread(); + if (state_ == kConnected || state_ == kDisconnecting) + { + // as if we received 0 byte in handleRead(); + handleClose(); + } +} + +const char* TcpConnection::stateToString() const +{ + switch (state_) + { + case kDisconnected: + return "kDisconnected"; + case kConnecting: + return "kConnecting"; + case kConnected: + return "kConnected"; + case kDisconnecting: + return "kDisconnecting"; + default: + return "unknown state"; + } +} + +void TcpConnection::setTcpNoDelay(bool on) +{ + socket_->setTcpNoDelay(on); +} + +void TcpConnection::startRead() +{ + loop_->runInLoop(std::bind(&TcpConnection::startReadInLoop, this)); +} + +void TcpConnection::startReadInLoop() +{ + loop_->assertInLoopThread(); + if (!reading_ || !channel_->isReading()) + { + channel_->enableReading(); + reading_ = true; + } +} + +void TcpConnection::stopRead() +{ + loop_->runInLoop(std::bind(&TcpConnection::stopReadInLoop, this)); +} + +void TcpConnection::stopReadInLoop() +{ + loop_->assertInLoopThread(); + if (reading_ || channel_->isReading()) + { + channel_->disableReading(); + reading_ = false; + } +} + +void TcpConnection::connectEstablished() +{ + loop_->assertInLoopThread(); + assert(state_ == kConnecting); + setState(kConnected); + channel_->tie(shared_from_this()); + channel_->enableReading(); + + connectionCallback_(shared_from_this()); +} + +void TcpConnection::connectDestroyed() +{ + loop_->assertInLoopThread(); + if (state_ == kConnected) + { + setState(kDisconnected); + channel_->disableAll(); + + connectionCallback_(shared_from_this()); + } + channel_->remove(); +} + +void TcpConnection::handleRead(Timestamp receiveTime) +{ + loop_->assertInLoopThread(); + int savedErrno = 0; + ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno); + if (n > 0) + { + messageCallback_(shared_from_this(), &inputBuffer_, receiveTime); + } + else if (n == 0) + { + handleClose(); + } + else + { + errno = savedErrno; + LOG_SYSERR << "TcpConnection::handleRead"; + handleError(); + } +} + +void TcpConnection::handleWrite() +{ + loop_->assertInLoopThread(); + if (channel_->isWriting()) + { + ssize_t n = sockets::write(channel_->fd(), + outputBuffer_.peek(), + outputBuffer_.readableBytes()); + if (n > 0) + { + outputBuffer_.retrieve(n); + if (outputBuffer_.readableBytes() == 0) + { + channel_->disableWriting(); + if (writeCompleteCallback_) + { + loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); + } + if (state_ == kDisconnecting) + { + shutdownInLoop(); + } + } + } + else + { + LOG_SYSERR << "TcpConnection::handleWrite"; + // if (state_ == kDisconnecting) + // { + // shutdownInLoop(); + // } + } + } + else + { + LOG_TRACE << "Connection fd = " << channel_->fd() + << " is down, no more writing"; + } +} + +void TcpConnection::handleClose() +{ + loop_->assertInLoopThread(); + LOG_TRACE << "fd = " << channel_->fd() << " state = " << stateToString(); + assert(state_ == kConnected || state_ == kDisconnecting); + // we don't close fd, leave it to dtor, so we can find leaks easily. + setState(kDisconnected); + channel_->disableAll(); + + TcpConnectionPtr guardThis(shared_from_this()); + connectionCallback_(guardThis); + // must be the last line + closeCallback_(guardThis); +} + +void TcpConnection::handleError() +{ + int err = sockets::getSocketError(channel_->fd()); + LOG_ERROR << "TcpConnection::handleError [" << name_ + << "] - SO_ERROR = " << err << " " << strerror_tl(err); +} + diff --git a/include/Third_Lib/muduo/net/TcpConnection.h b/include/Third_Lib/muduo/net/TcpConnection.h new file mode 100644 index 0000000..cb76331 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpConnection.h @@ -0,0 +1,161 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPCONNECTION_H +#define MUDUO_NET_TCPCONNECTION_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/Buffer.h" +#include "muduo/net/InetAddress.h" + +#include + +#include + +// struct tcp_info is in +struct tcp_info; + +namespace muduo +{ +namespace net +{ + +class Channel; +class EventLoop; +class Socket; + +/// +/// TCP connection, for both client and server usage. +/// +/// This is an interface class, so don't expose too much details. +class TcpConnection : noncopyable, + public std::enable_shared_from_this +{ + public: + /// Constructs a TcpConnection with a connected sockfd + /// + /// User should not create this object. + TcpConnection(EventLoop* loop, + const string& name, + int sockfd, + const InetAddress& localAddr, + const InetAddress& peerAddr); + ~TcpConnection(); + + EventLoop* getLoop() const { return loop_; } + const string& name() const { return name_; } + const InetAddress& localAddress() const { return localAddr_; } + const InetAddress& peerAddress() const { return peerAddr_; } + bool connected() const { return state_ == kConnected; } + bool disconnected() const { return state_ == kDisconnected; } + // return true if success. + bool getTcpInfo(struct tcp_info*) const; + string getTcpInfoString() const; + + // void send(string&& message); // C++11 + void send(const void* message, int len); + void send(const StringPiece& message); + // void send(Buffer&& message); // C++11 + void send(Buffer* message); // this one will swap data + void shutdown(); // NOT thread safe, no simultaneous calling + // void shutdownAndForceCloseAfter(double seconds); // NOT thread safe, no simultaneous calling + void forceClose(); + void forceCloseWithDelay(double seconds); + void setTcpNoDelay(bool on); + // reading or not + void startRead(); + void stopRead(); + bool isReading() const { return reading_; }; // NOT thread safe, may race with start/stopReadInLoop + + void setContext(const boost::any& context) + { context_ = context; } + + const boost::any& getContext() const + { return context_; } + + boost::any* getMutableContext() + { return &context_; } + + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } + + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + + void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark) + { highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark; } + + /// Advanced interface + Buffer* inputBuffer() + { return &inputBuffer_; } + + Buffer* outputBuffer() + { return &outputBuffer_; } + + /// Internal use only. + void setCloseCallback(const CloseCallback& cb) + { closeCallback_ = cb; } + + // called when TcpServer accepts a new connection + void connectEstablished(); // should be called only once + // called when TcpServer has removed me from its map + void connectDestroyed(); // should be called only once + + private: + enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting }; + void handleRead(Timestamp receiveTime); + void handleWrite(); + void handleClose(); + void handleError(); + // void sendInLoop(string&& message); + void sendInLoop(const StringPiece& message); + void sendInLoop(const void* message, size_t len); + void shutdownInLoop(); + // void shutdownAndForceCloseInLoop(double seconds); + void forceCloseInLoop(); + void setState(StateE s) { state_ = s; } + const char* stateToString() const; + void startReadInLoop(); + void stopReadInLoop(); + + EventLoop* loop_; + const string name_; + StateE state_; // FIXME: use atomic variable + bool reading_; + // we don't expose those classes to client. + std::unique_ptr socket_; + std::unique_ptr channel_; + const InetAddress localAddr_; + const InetAddress peerAddr_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + HighWaterMarkCallback highWaterMarkCallback_; + CloseCallback closeCallback_; + size_t highWaterMark_; + Buffer inputBuffer_; + Buffer outputBuffer_; // FIXME: use list as output buffer. + boost::any context_; + // FIXME: creationTime_, lastReceiveTime_ + // bytesReceived_, bytesSent_ +}; + +typedef std::shared_ptr TcpConnectionPtr; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPCONNECTION_H diff --git a/include/Third_Lib/muduo/net/TcpServer.cc b/include/Third_Lib/muduo/net/TcpServer.cc new file mode 100644 index 0000000..e4f8e24 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpServer.cc @@ -0,0 +1,118 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/TcpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Acceptor.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThreadPool.h" +#include "muduo/net/SocketsOps.h" + +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +TcpServer::TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& nameArg, + Option option) + : loop_(CHECK_NOTNULL(loop)), + ipPort_(listenAddr.toIpPort()), + name_(nameArg), + acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), + threadPool_(new EventLoopThreadPool(loop, name_)), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), + nextConnId_(1) +{ + acceptor_->setNewConnectionCallback( + std::bind(&TcpServer::newConnection, this, _1, _2)); +} + +TcpServer::~TcpServer() +{ + loop_->assertInLoopThread(); + LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; + + for (auto& item : connections_) + { + TcpConnectionPtr conn(item.second); + item.second.reset(); + conn->getLoop()->runInLoop( + std::bind(&TcpConnection::connectDestroyed, conn)); + } +} + +void TcpServer::setThreadNum(int numThreads) +{ + assert(0 <= numThreads); + threadPool_->setThreadNum(numThreads); +} + +void TcpServer::start() +{ + if (started_.getAndSet(1) == 0) + { + threadPool_->start(threadInitCallback_); + + assert(!acceptor_->listening()); + loop_->runInLoop( + std::bind(&Acceptor::listen, get_pointer(acceptor_))); + } +} + +void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) +{ + loop_->assertInLoopThread(); + EventLoop* ioLoop = threadPool_->getNextLoop(); + char buf[64]; + snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_); + ++nextConnId_; + string connName = name_ + buf; + + LOG_INFO << "TcpServer::newConnection [" << name_ + << "] - new connection [" << connName + << "] from " << peerAddr.toIpPort(); + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection + // FIXME use make_shared if necessary + TcpConnectionPtr conn(new TcpConnection(ioLoop, + connName, + sockfd, + localAddr, + peerAddr)); + connections_[connName] = conn; + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); + conn->setCloseCallback( + std::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe + ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn)); +} + +void TcpServer::removeConnection(const TcpConnectionPtr& conn) +{ + // FIXME: unsafe + loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn)); +} + +void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ + << "] - connection " << conn->name(); + size_t n = connections_.erase(conn->name()); + (void)n; + assert(n == 1); + EventLoop* ioLoop = conn->getLoop(); + ioLoop->queueInLoop( + std::bind(&TcpConnection::connectDestroyed, conn)); +} + diff --git a/include/Third_Lib/muduo/net/TcpServer.h b/include/Third_Lib/muduo/net/TcpServer.h new file mode 100644 index 0000000..3fbfead --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpServer.h @@ -0,0 +1,120 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPSERVER_H +#define MUDUO_NET_TCPSERVER_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Types.h" +#include "muduo/net/TcpConnection.h" + +#include + +namespace muduo +{ +namespace net +{ + +class Acceptor; +class EventLoop; +class EventLoopThreadPool; + +/// +/// TCP server, supports single-threaded and thread-pool models. +/// +/// This is an interface class, so don't expose too much details. +class TcpServer : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + enum Option + { + kNoReusePort, + kReusePort, + }; + + //TcpServer(EventLoop* loop, const InetAddress& listenAddr); + TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& nameArg, + Option option = kNoReusePort); + ~TcpServer(); // force out-line dtor, for std::unique_ptr members. + + const string& ipPort() const { return ipPort_; } + const string& name() const { return name_; } + EventLoop* getLoop() const { return loop_; } + + /// Set the number of threads for handling input. + /// + /// Always accepts new connection in loop's thread. + /// Must be called before @c start + /// @param numThreads + /// - 0 means all I/O in loop's thread, no thread will created. + /// this is the default value. + /// - 1 means all I/O in another thread. + /// - N means a thread pool with N threads, new connections + /// are assigned on a round-robin basis. + void setThreadNum(int numThreads); + void setThreadInitCallback(const ThreadInitCallback& cb) + { threadInitCallback_ = cb; } + /// valid after calling start() + std::shared_ptr threadPool() + { return threadPool_; } + + /// Starts the server if it's not listening. + /// + /// It's harmless to call it multiple times. + /// Thread safe. + void start(); + + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } + + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + + private: + /// Not thread safe, but in loop + void newConnection(int sockfd, const InetAddress& peerAddr); + /// Thread safe. + void removeConnection(const TcpConnectionPtr& conn); + /// Not thread safe, but in loop + void removeConnectionInLoop(const TcpConnectionPtr& conn); + + typedef std::map ConnectionMap; + + EventLoop* loop_; // the acceptor loop + const string ipPort_; + const string name_; + std::unique_ptr acceptor_; // avoid revealing Acceptor + std::shared_ptr threadPool_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + ThreadInitCallback threadInitCallback_; + AtomicInt32 started_; + // always in loop thread + int nextConnId_; + ConnectionMap connections_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPSERVER_H diff --git a/include/Third_Lib/muduo/net/Timer.cc b/include/Third_Lib/muduo/net/Timer.cc new file mode 100644 index 0000000..a4d4433 --- /dev/null +++ b/include/Third_Lib/muduo/net/Timer.cc @@ -0,0 +1,26 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Timer.h" + +using namespace muduo; +using namespace muduo::net; + +AtomicInt64 Timer::s_numCreated_; + +void Timer::restart(Timestamp now) +{ + if (repeat_) + { + expiration_ = addTime(now, interval_); + } + else + { + expiration_ = Timestamp::invalid(); + } +} diff --git a/include/Third_Lib/muduo/net/Timer.h b/include/Third_Lib/muduo/net/Timer.h new file mode 100644 index 0000000..904584e --- /dev/null +++ b/include/Third_Lib/muduo/net/Timer.h @@ -0,0 +1,63 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_TIMER_H +#define MUDUO_NET_TIMER_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" + +namespace muduo +{ +namespace net +{ + +/// +/// Internal class for timer event. +/// +class Timer : noncopyable +{ + public: + Timer(TimerCallback cb, Timestamp when, double interval) + : callback_(std::move(cb)), + expiration_(when), + interval_(interval), + repeat_(interval > 0.0), + sequence_(s_numCreated_.incrementAndGet()) + { } + + void run() const + { + callback_(); + } + + Timestamp expiration() const { return expiration_; } + bool repeat() const { return repeat_; } + int64_t sequence() const { return sequence_; } + + void restart(Timestamp now); + + static int64_t numCreated() { return s_numCreated_.get(); } + + private: + const TimerCallback callback_; + Timestamp expiration_; + const double interval_; + const bool repeat_; + const int64_t sequence_; + + static AtomicInt64 s_numCreated_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TIMER_H diff --git a/include/Third_Lib/muduo/net/TimerId.h b/include/Third_Lib/muduo/net/TimerId.h new file mode 100644 index 0000000..fcc5264 --- /dev/null +++ b/include/Third_Lib/muduo/net/TimerId.h @@ -0,0 +1,53 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TIMERID_H +#define MUDUO_NET_TIMERID_H + +#include "muduo/base/copyable.h" + +namespace muduo +{ +namespace net +{ + +class Timer; + +/// +/// An opaque identifier, for canceling Timer. +/// +class TimerId : public muduo::copyable +{ + public: + TimerId() + : timer_(NULL), + sequence_(0) + { + } + + TimerId(Timer* timer, int64_t seq) + : timer_(timer), + sequence_(seq) + { + } + + // default copy-ctor, dtor and assignment are okay + + friend class TimerQueue; + + private: + Timer* timer_; + int64_t sequence_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TIMERID_H diff --git a/include/Third_Lib/muduo/net/TimerQueue.cc b/include/Third_Lib/muduo/net/TimerQueue.cc new file mode 100644 index 0000000..89119ae --- /dev/null +++ b/include/Third_Lib/muduo/net/TimerQueue.cc @@ -0,0 +1,260 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +#include "muduo/net/TimerQueue.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/Timer.h" +#include "muduo/net/TimerId.h" + +#include +#include + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +int createTimerfd() +{ + int timerfd = ::timerfd_create(CLOCK_MONOTONIC, + TFD_NONBLOCK | TFD_CLOEXEC); + if (timerfd < 0) + { + LOG_SYSFATAL << "Failed in timerfd_create"; + } + return timerfd; +} + +struct timespec howMuchTimeFromNow(Timestamp when) +{ + int64_t microseconds = when.microSecondsSinceEpoch() + - Timestamp::now().microSecondsSinceEpoch(); + if (microseconds < 100) + { + microseconds = 100; + } + struct timespec ts; + ts.tv_sec = static_cast( + microseconds / Timestamp::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast( + (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); + return ts; +} + +void readTimerfd(int timerfd, Timestamp now) +{ + uint64_t howmany; + ssize_t n = ::read(timerfd, &howmany, sizeof howmany); + LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); + if (n != sizeof howmany) + { + LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; + } +} + +void resetTimerfd(int timerfd, Timestamp expiration) +{ + // wake up loop by timerfd_settime() + struct itimerspec newValue; + struct itimerspec oldValue; + memZero(&newValue, sizeof newValue); + memZero(&oldValue, sizeof oldValue); + newValue.it_value = howMuchTimeFromNow(expiration); + int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); + if (ret) + { + LOG_SYSERR << "timerfd_settime()"; + } +} + +} // namespace detail +} // namespace net +} // namespace muduo + +using namespace muduo; +using namespace muduo::net; +using namespace muduo::net::detail; + +TimerQueue::TimerQueue(EventLoop* loop) + : loop_(loop), + timerfd_(createTimerfd()), + timerfdChannel_(loop, timerfd_), + timers_(), + callingExpiredTimers_(false) +{ + timerfdChannel_.setReadCallback( + std::bind(&TimerQueue::handleRead, this)); + // we are always reading the timerfd, we disarm it with timerfd_settime. + timerfdChannel_.enableReading(); +} + +TimerQueue::~TimerQueue() +{ + timerfdChannel_.disableAll(); + timerfdChannel_.remove(); + ::close(timerfd_); + // do not remove channel, since we're in EventLoop::dtor(); + for (const Entry& timer : timers_) + { + delete timer.second; + } +} + +TimerId TimerQueue::addTimer(TimerCallback cb, + Timestamp when, + double interval) +{ + Timer* timer = new Timer(std::move(cb), when, interval); + loop_->runInLoop( + std::bind(&TimerQueue::addTimerInLoop, this, timer)); + return TimerId(timer, timer->sequence()); +} + +void TimerQueue::cancel(TimerId timerId) +{ + loop_->runInLoop( + std::bind(&TimerQueue::cancelInLoop, this, timerId)); +} + +void TimerQueue::addTimerInLoop(Timer* timer) +{ + loop_->assertInLoopThread(); + bool earliestChanged = insert(timer); + + if (earliestChanged) + { + resetTimerfd(timerfd_, timer->expiration()); + } +} + +void TimerQueue::cancelInLoop(TimerId timerId) +{ + loop_->assertInLoopThread(); + assert(timers_.size() == activeTimers_.size()); + ActiveTimer timer(timerId.timer_, timerId.sequence_); + ActiveTimerSet::iterator it = activeTimers_.find(timer); + if (it != activeTimers_.end()) + { + size_t n = timers_.erase(Entry(it->first->expiration(), it->first)); + assert(n == 1); (void)n; + delete it->first; // FIXME: no delete please + activeTimers_.erase(it); + } + else if (callingExpiredTimers_) + { + cancelingTimers_.insert(timer); + } + assert(timers_.size() == activeTimers_.size()); +} + +void TimerQueue::handleRead() +{ + loop_->assertInLoopThread(); + Timestamp now(Timestamp::now()); + readTimerfd(timerfd_, now); + + std::vector expired = getExpired(now); + + callingExpiredTimers_ = true; + cancelingTimers_.clear(); + // safe to callback outside critical section + for (const Entry& it : expired) + { + it.second->run(); + } + callingExpiredTimers_ = false; + + reset(expired, now); +} + +std::vector TimerQueue::getExpired(Timestamp now) +{ + assert(timers_.size() == activeTimers_.size()); + std::vector expired; + Entry sentry(now, reinterpret_cast(UINTPTR_MAX)); + TimerList::iterator end = timers_.lower_bound(sentry); + assert(end == timers_.end() || now < end->first); + std::copy(timers_.begin(), end, back_inserter(expired)); + timers_.erase(timers_.begin(), end); + + for (const Entry& it : expired) + { + ActiveTimer timer(it.second, it.second->sequence()); + size_t n = activeTimers_.erase(timer); + assert(n == 1); (void)n; + } + + assert(timers_.size() == activeTimers_.size()); + return expired; +} + +void TimerQueue::reset(const std::vector& expired, Timestamp now) +{ + Timestamp nextExpire; + + for (const Entry& it : expired) + { + ActiveTimer timer(it.second, it.second->sequence()); + if (it.second->repeat() + && cancelingTimers_.find(timer) == cancelingTimers_.end()) + { + it.second->restart(now); + insert(it.second); + } + else + { + // FIXME move to a free list + delete it.second; // FIXME: no delete please + } + } + + if (!timers_.empty()) + { + nextExpire = timers_.begin()->second->expiration(); + } + + if (nextExpire.valid()) + { + resetTimerfd(timerfd_, nextExpire); + } +} + +bool TimerQueue::insert(Timer* timer) +{ + loop_->assertInLoopThread(); + assert(timers_.size() == activeTimers_.size()); + bool earliestChanged = false; + Timestamp when = timer->expiration(); + TimerList::iterator it = timers_.begin(); + if (it == timers_.end() || when < it->first) + { + earliestChanged = true; + } + { + std::pair result + = timers_.insert(Entry(when, timer)); + assert(result.second); (void)result; + } + { + std::pair result + = activeTimers_.insert(ActiveTimer(timer, timer->sequence())); + assert(result.second); (void)result; + } + + assert(timers_.size() == activeTimers_.size()); + return earliestChanged; +} + diff --git a/include/Third_Lib/muduo/net/TimerQueue.h b/include/Third_Lib/muduo/net/TimerQueue.h new file mode 100644 index 0000000..85da6b7 --- /dev/null +++ b/include/Third_Lib/muduo/net/TimerQueue.h @@ -0,0 +1,86 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_TIMERQUEUE_H +#define MUDUO_NET_TIMERQUEUE_H + +#include +#include + +#include "muduo/base/Mutex.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/Channel.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; +class Timer; +class TimerId; + +/// +/// A best efforts timer queue. +/// No guarantee that the callback will be on time. +/// +class TimerQueue : noncopyable +{ + public: + explicit TimerQueue(EventLoop* loop); + ~TimerQueue(); + + /// + /// Schedules the callback to be run at given time, + /// repeats if @c interval > 0.0. + /// + /// Must be thread safe. Usually be called from other threads. + TimerId addTimer(TimerCallback cb, + Timestamp when, + double interval); + + void cancel(TimerId timerId); + + private: + + // FIXME: use unique_ptr instead of raw pointers. + // This requires heterogeneous comparison lookup (N3465) from C++14 + // so that we can find an T* in a set>. + typedef std::pair Entry; + typedef std::set TimerList; + typedef std::pair ActiveTimer; + typedef std::set ActiveTimerSet; + + void addTimerInLoop(Timer* timer); + void cancelInLoop(TimerId timerId); + // called when timerfd alarms + void handleRead(); + // move out all expired timers + std::vector getExpired(Timestamp now); + void reset(const std::vector& expired, Timestamp now); + + bool insert(Timer* timer); + + EventLoop* loop_; + const int timerfd_; + Channel timerfdChannel_; + // Timer list sorted by expiration + TimerList timers_; + + // for cancel() + ActiveTimerSet activeTimers_; + bool callingExpiredTimers_; /* atomic */ + ActiveTimerSet cancelingTimers_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_TIMERQUEUE_H diff --git a/include/Third_Lib/muduo/net/ZlibStream.h b/include/Third_Lib/muduo/net/ZlibStream.h new file mode 100644 index 0000000..0f143b0 --- /dev/null +++ b/include/Third_Lib/muduo/net/ZlibStream.h @@ -0,0 +1,145 @@ +#pragma once + +#include "muduo/base/noncopyable.h" +#include "muduo/net/Buffer.h" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#include + +namespace muduo +{ +namespace net +{ + +// input is zlib compressed data, output uncompressed data +// FIXME: finish this +class ZlibInputStream : noncopyable +{ + public: + explicit ZlibInputStream(Buffer* output) + : output_(output), + zerror_(Z_OK) + { + memZero(&zstream_, sizeof zstream_); + zerror_ = inflateInit(&zstream_); + } + + ~ZlibInputStream() + { + finish(); + } + + bool write(StringPiece buf); + bool write(Buffer* input); + bool finish(); + // inflateEnd(&zstream_); + + private: + int decompress(int flush); + + Buffer* output_; + z_stream zstream_; + int zerror_; +}; + +// input is uncompressed data, output zlib compressed data +class ZlibOutputStream : noncopyable +{ + public: + explicit ZlibOutputStream(Buffer* output) + : output_(output), + zerror_(Z_OK), + bufferSize_(1024) + { + memZero(&zstream_, sizeof zstream_); + zerror_ = deflateInit(&zstream_, Z_DEFAULT_COMPRESSION); + } + + ~ZlibOutputStream() + { + finish(); + } + + // Return last error message or NULL if no error. + const char* zlibErrorMessage() const { return zstream_.msg; } + + int zlibErrorCode() const { return zerror_; } + int64_t inputBytes() const { return zstream_.total_in; } + int64_t outputBytes() const { return zstream_.total_out; } + int internalOutputBufferSize() const { return bufferSize_; } + + bool write(StringPiece buf) + { + if (zerror_ != Z_OK) + return false; + + assert(zstream_.next_in == NULL && zstream_.avail_in == 0); + void* in = const_cast(buf.data()); + zstream_.next_in = static_cast(in); + zstream_.avail_in = buf.size(); + while (zstream_.avail_in > 0 && zerror_ == Z_OK) + { + zerror_ = compress(Z_NO_FLUSH); + } + if (zstream_.avail_in == 0) + { + assert(static_cast(zstream_.next_in) == buf.end()); + zstream_.next_in = NULL; + } + return zerror_ == Z_OK; + } + + // compress input as much as possible, not guarantee consuming all data. + bool write(Buffer* input) + { + if (zerror_ != Z_OK) + return false; + + void* in = const_cast(input->peek()); + zstream_.next_in = static_cast(in); + zstream_.avail_in = static_cast(input->readableBytes()); + if (zstream_.avail_in > 0 && zerror_ == Z_OK) + { + zerror_ = compress(Z_NO_FLUSH); + } + input->retrieve(input->readableBytes() - zstream_.avail_in); + return zerror_ == Z_OK; + } + + bool finish() + { + if (zerror_ != Z_OK) + return false; + + while (zerror_ == Z_OK) + { + zerror_ = compress(Z_FINISH); + } + zerror_ = deflateEnd(&zstream_); + bool ok = zerror_ == Z_OK; + zerror_ = Z_STREAM_END; + return ok; + } + + private: + int compress(int flush) + { + output_->ensureWritableBytes(bufferSize_); + zstream_.next_out = reinterpret_cast(output_->beginWrite()); + zstream_.avail_out = static_cast(output_->writableBytes()); + int error = ::deflate(&zstream_, flush); + output_->hasWritten(output_->writableBytes() - zstream_.avail_out); + if (output_->writableBytes() == 0 && bufferSize_ < 65536) + { + bufferSize_ *= 2; + } + return error; + } + + Buffer* output_; + z_stream zstream_; + int zerror_; + int bufferSize_; +}; + +} // namespace net +} // namespace muduo diff --git a/include/Third_Lib/muduo/net/boilerplate.cc b/include/Third_Lib/muduo/net/boilerplate.cc new file mode 100644 index 0000000..d0ebe26 --- /dev/null +++ b/include/Third_Lib/muduo/net/boilerplate.cc @@ -0,0 +1,15 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/BoilerPlate.h" + +using namespace muduo; +using namespace muduo::net; + + diff --git a/include/Third_Lib/muduo/net/boilerplate.h b/include/Third_Lib/muduo/net/boilerplate.h new file mode 100644 index 0000000..780661c --- /dev/null +++ b/include/Third_Lib/muduo/net/boilerplate.h @@ -0,0 +1,32 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_BOILERPLATE_H +#define MUDUO_NET_BOILERPLATE_H + +#include "muduo/base/noncopyable.h" + +namespace muduo +{ +namespace net +{ + +class BoilerPlate : noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_BOILERPLATE_H diff --git a/include/Third_Lib/muduo/net/http/BUILD.bazel b/include/Third_Lib/muduo/net/http/BUILD.bazel new file mode 100644 index 0000000..08b98a4 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/BUILD.bazel @@ -0,0 +1,9 @@ +cc_library( + name = "http", + srcs = glob(["*.cc"]), + hdrs = glob(["*.h"]), + visibility = ["//visibility:public"], + deps = [ + "//muduo/net", + ], +) diff --git a/include/Third_Lib/muduo/net/http/CMakeLists.txt b/include/Third_Lib/muduo/net/http/CMakeLists.txt new file mode 100644 index 0000000..51dd981 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/CMakeLists.txt @@ -0,0 +1,30 @@ +set(http_SRCS + HttpServer.cc + HttpResponse.cc + HttpContext.cc + ) + +add_library(muduo_http ${http_SRCS}) +target_link_libraries(muduo_http muduo_net) + +install(TARGETS muduo_http DESTINATION lib) +set(HEADERS + HttpContext.h + HttpRequest.h + HttpResponse.h + HttpServer.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/http) + +if(MUDUO_BUILD_EXAMPLES) +add_executable(httpserver_test tests/HttpServer_test.cc) +target_link_libraries(httpserver_test muduo_http) + +if(BOOSTTEST_LIBRARY) +add_executable(httprequest_unittest tests/HttpRequest_unittest.cc) +target_link_libraries(httprequest_unittest muduo_http boost_unit_test_framework) +endif() + +endif() + +# add_subdirectory(tests) diff --git a/include/Third_Lib/muduo/net/http/HttpContext.cc b/include/Third_Lib/muduo/net/http/HttpContext.cc new file mode 100644 index 0000000..bef3a80 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpContext.cc @@ -0,0 +1,118 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Buffer.h" +#include "muduo/net/http/HttpContext.h" + +using namespace muduo; +using namespace muduo::net; + +bool HttpContext::processRequestLine(const char* begin, const char* end) +{ + bool succeed = false; + const char* start = begin; + const char* space = std::find(start, end, ' '); + if (space != end && request_.setMethod(start, space)) + { + start = space+1; + space = std::find(start, end, ' '); + if (space != end) + { + const char* question = std::find(start, space, '?'); + if (question != space) + { + request_.setPath(start, question); + request_.setQuery(question, space); + } + else + { + request_.setPath(start, space); + } + start = space+1; + succeed = end-start == 8 && std::equal(start, end-1, "HTTP/1."); + if (succeed) + { + if (*(end-1) == '1') + { + request_.setVersion(HttpRequest::kHttp11); + } + else if (*(end-1) == '0') + { + request_.setVersion(HttpRequest::kHttp10); + } + else + { + succeed = false; + } + } + } + } + return succeed; +} + +// return false if any error +bool HttpContext::parseRequest(Buffer* buf, Timestamp receiveTime) +{ + bool ok = true; + bool hasMore = true; + while (hasMore) + { + if (state_ == kExpectRequestLine) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + ok = processRequestLine(buf->peek(), crlf); + if (ok) + { + request_.setReceiveTime(receiveTime); + buf->retrieveUntil(crlf + 2); + state_ = kExpectHeaders; + } + else + { + hasMore = false; + } + } + else + { + hasMore = false; + } + } + else if (state_ == kExpectHeaders) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + const char* colon = std::find(buf->peek(), crlf, ':'); + if (colon != crlf) + { + request_.addHeader(buf->peek(), colon, crlf); + } + else + { + // empty line, end of header + // FIXME: + state_ = kGotAll; + hasMore = false; + } + buf->retrieveUntil(crlf + 2); + } + else + { + hasMore = false; + } + } + else if (state_ == kExpectBody) + { + // FIXME: + } + } + return ok; +} diff --git a/include/Third_Lib/muduo/net/http/HttpContext.h b/include/Third_Lib/muduo/net/http/HttpContext.h new file mode 100644 index 0000000..4beee5c --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpContext.h @@ -0,0 +1,72 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H +#define MUDUO_NET_HTTP_HTTPCONTEXT_H + +#include "muduo/base/copyable.h" + +#include "muduo/net/http/HttpRequest.h" + +namespace muduo +{ +namespace net +{ + +class Buffer; + +class HttpContext : public muduo::copyable +{ + public: + enum HttpRequestParseState + { + kExpectRequestLine, + kExpectHeaders, + kExpectBody, + kGotAll, + }; + + HttpContext() + : state_(kExpectRequestLine) + { + } + + // default copy-ctor, dtor and assignment are fine + + // return false if any error + bool parseRequest(Buffer* buf, Timestamp receiveTime); + + bool gotAll() const + { return state_ == kGotAll; } + + void reset() + { + state_ = kExpectRequestLine; + HttpRequest dummy; + request_.swap(dummy); + } + + const HttpRequest& request() const + { return request_; } + + HttpRequest& request() + { return request_; } + + private: + bool processRequestLine(const char* begin, const char* end); + + HttpRequestParseState state_; + HttpRequest request_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPCONTEXT_H diff --git a/include/Third_Lib/muduo/net/http/HttpRequest.h b/include/Third_Lib/muduo/net/http/HttpRequest.h new file mode 100644 index 0000000..9c70c5d --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpRequest.h @@ -0,0 +1,187 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H +#define MUDUO_NET_HTTP_HTTPREQUEST_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Timestamp.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ +namespace net +{ + +class HttpRequest : public muduo::copyable +{ + public: + enum Method + { + kInvalid, kGet, kPost, kHead, kPut, kDelete + }; + enum Version + { + kUnknown, kHttp10, kHttp11 + }; + + HttpRequest() + : method_(kInvalid), + version_(kUnknown) + { + } + + void setVersion(Version v) + { + version_ = v; + } + + Version getVersion() const + { return version_; } + + bool setMethod(const char* start, const char* end) + { + assert(method_ == kInvalid); + string m(start, end); + if (m == "GET") + { + method_ = kGet; + } + else if (m == "POST") + { + method_ = kPost; + } + else if (m == "HEAD") + { + method_ = kHead; + } + else if (m == "PUT") + { + method_ = kPut; + } + else if (m == "DELETE") + { + method_ = kDelete; + } + else + { + method_ = kInvalid; + } + return method_ != kInvalid; + } + + Method method() const + { return method_; } + + const char* methodString() const + { + const char* result = "UNKNOWN"; + switch(method_) + { + case kGet: + result = "GET"; + break; + case kPost: + result = "POST"; + break; + case kHead: + result = "HEAD"; + break; + case kPut: + result = "PUT"; + break; + case kDelete: + result = "DELETE"; + break; + default: + break; + } + return result; + } + + void setPath(const char* start, const char* end) + { + path_.assign(start, end); + } + + const string& path() const + { return path_; } + + void setQuery(const char* start, const char* end) + { + query_.assign(start, end); + } + + const string& query() const + { return query_; } + + void setReceiveTime(Timestamp t) + { receiveTime_ = t; } + + Timestamp receiveTime() const + { return receiveTime_; } + + void addHeader(const char* start, const char* colon, const char* end) + { + string field(start, colon); + ++colon; + while (colon < end && isspace(*colon)) + { + ++colon; + } + string value(colon, end); + while (!value.empty() && isspace(value[value.size()-1])) + { + value.resize(value.size()-1); + } + headers_[field] = value; + } + + string getHeader(const string& field) const + { + string result; + std::map::const_iterator it = headers_.find(field); + if (it != headers_.end()) + { + result = it->second; + } + return result; + } + + const std::map& headers() const + { return headers_; } + + void swap(HttpRequest& that) + { + std::swap(method_, that.method_); + std::swap(version_, that.version_); + path_.swap(that.path_); + query_.swap(that.query_); + receiveTime_.swap(that.receiveTime_); + headers_.swap(that.headers_); + } + + private: + Method method_; + Version version_; + string path_; + string query_; + Timestamp receiveTime_; + std::map headers_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPREQUEST_H diff --git a/include/Third_Lib/muduo/net/http/HttpResponse.cc b/include/Third_Lib/muduo/net/http/HttpResponse.cc new file mode 100644 index 0000000..0e2e74d --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpResponse.cc @@ -0,0 +1,47 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/Buffer.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void HttpResponse::appendToBuffer(Buffer* output) const +{ + char buf[32]; + snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); + output->append(buf); + output->append(statusMessage_); + output->append("\r\n"); + + if (closeConnection_) + { + output->append("Connection: close\r\n"); + } + else + { + snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size()); + output->append(buf); + output->append("Connection: Keep-Alive\r\n"); + } + + for (const auto& header : headers_) + { + output->append(header.first); + output->append(": "); + output->append(header.second); + output->append("\r\n"); + } + + output->append("\r\n"); + output->append(body_); +} diff --git a/include/Third_Lib/muduo/net/http/HttpResponse.h b/include/Third_Lib/muduo/net/http/HttpResponse.h new file mode 100644 index 0000000..eb3910f --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpResponse.h @@ -0,0 +1,79 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H +#define MUDUO_NET_HTTP_HTTPRESPONSE_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ +namespace net +{ + +class Buffer; +class HttpResponse : public muduo::copyable +{ + public: + enum HttpStatusCode + { + kUnknown, + k200Ok = 200, + k301MovedPermanently = 301, + k400BadRequest = 400, + k404NotFound = 404, + }; + + explicit HttpResponse(bool close) + : statusCode_(kUnknown), + closeConnection_(close) + { + } + + void setStatusCode(HttpStatusCode code) + { statusCode_ = code; } + + void setStatusMessage(const string& message) + { statusMessage_ = message; } + + void setCloseConnection(bool on) + { closeConnection_ = on; } + + bool closeConnection() const + { return closeConnection_; } + + void setContentType(const string& contentType) + { addHeader("Content-Type", contentType); } + + // FIXME: replace string with StringPiece + void addHeader(const string& key, const string& value) + { headers_[key] = value; } + + void setBody(const string& body) + { body_ = body; } + + void appendToBuffer(Buffer* output) const; + + private: + std::map headers_; + HttpStatusCode statusCode_; + // FIXME: add http version + string statusMessage_; + bool closeConnection_; + string body_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPRESPONSE_H diff --git a/include/Third_Lib/muduo/net/http/HttpServer.cc b/include/Third_Lib/muduo/net/http/HttpServer.cc new file mode 100644 index 0000000..f7d4678 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpServer.cc @@ -0,0 +1,100 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/http/HttpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/http/HttpContext.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +void defaultHttpCallback(const HttpRequest&, HttpResponse* resp) +{ + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); +} + +} // namespace detail +} // namespace net +} // namespace muduo + +HttpServer::HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name, + TcpServer::Option option) + : server_(loop, listenAddr, name, option), + httpCallback_(detail::defaultHttpCallback) +{ + server_.setConnectionCallback( + std::bind(&HttpServer::onConnection, this, _1)); + server_.setMessageCallback( + std::bind(&HttpServer::onMessage, this, _1, _2, _3)); +} + +void HttpServer::start() +{ + LOG_WARN << "HttpServer[" << server_.name() + << "] starts listening on " << server_.ipPort(); + server_.start(); +} + +void HttpServer::onConnection(const TcpConnectionPtr& conn) +{ + if (conn->connected()) + { + conn->setContext(HttpContext()); + } +} + +void HttpServer::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + HttpContext* context = boost::any_cast(conn->getMutableContext()); + + if (!context->parseRequest(buf, receiveTime)) + { + conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); + conn->shutdown(); + } + + if (context->gotAll()) + { + onRequest(conn, context->request()); + context->reset(); + } +} + +void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) +{ + const string& connection = req.getHeader("Connection"); + bool close = connection == "close" || + (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive"); + HttpResponse response(close); + httpCallback_(req, &response); + Buffer buf; + response.appendToBuffer(&buf); + conn->send(&buf); + if (response.closeConnection()) + { + conn->shutdown(); + } +} + diff --git a/include/Third_Lib/muduo/net/http/HttpServer.h b/include/Third_Lib/muduo/net/http/HttpServer.h new file mode 100644 index 0000000..9609a11 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpServer.h @@ -0,0 +1,68 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPSERVER_H +#define MUDUO_NET_HTTP_HTTPSERVER_H + +#include "muduo/net/TcpServer.h" + +namespace muduo +{ +namespace net +{ + +class HttpRequest; +class HttpResponse; + +/// A simple embeddable HTTP server designed for report status of a program. +/// It is not a fully HTTP 1.1 compliant server, but provides minimum features +/// that can communicate with HttpClient and Web browser. +/// It is synchronous, just like Java Servlet. +class HttpServer : noncopyable +{ + public: + typedef std::function HttpCallback; + + HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name, + TcpServer::Option option = TcpServer::kNoReusePort); + + EventLoop* getLoop() const { return server_.getLoop(); } + + /// Not thread safe, callback be registered before calling start(). + void setHttpCallback(const HttpCallback& cb) + { + httpCallback_ = cb; + } + + void setThreadNum(int numThreads) + { + server_.setThreadNum(numThreads); + } + + void start(); + + private: + void onConnection(const TcpConnectionPtr& conn); + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + void onRequest(const TcpConnectionPtr&, const HttpRequest&); + + TcpServer server_; + HttpCallback httpCallback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPSERVER_H diff --git a/include/Third_Lib/muduo/net/http/tests/HttpRequest_unittest.cc b/include/Third_Lib/muduo/net/http/tests/HttpRequest_unittest.cc new file mode 100644 index 0000000..cb89305 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/tests/HttpRequest_unittest.cc @@ -0,0 +1,79 @@ +#include "muduo/net/http/HttpContext.h" +#include "muduo/net/Buffer.h" + +//#define BOOST_TEST_MODULE BufferTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::Timestamp; +using muduo::net::Buffer; +using muduo::net::HttpContext; +using muduo::net::HttpRequest; + +BOOST_AUTO_TEST_CASE(testParseRequestAllInOne) +{ + HttpContext context; + Buffer input; + input.append("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "\r\n"); + + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); +} + +BOOST_AUTO_TEST_CASE(testParseRequestInTwoPieces) +{ + string all("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "\r\n"); + + for (size_t sz1 = 0; sz1 < all.size(); ++sz1) + { + HttpContext context; + Buffer input; + input.append(all.c_str(), sz1); + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(!context.gotAll()); + + size_t sz2 = all.size() - sz1; + input.append(all.c_str() + sz1, sz2); + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); + } +} + +BOOST_AUTO_TEST_CASE(testParseRequestEmptyHeaderValue) +{ + HttpContext context; + Buffer input; + input.append("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "User-Agent:\r\n" + "Accept-Encoding: \r\n" + "\r\n"); + + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); + BOOST_CHECK_EQUAL(request.getHeader("Accept-Encoding"), string("")); +} diff --git a/include/Third_Lib/muduo/net/http/tests/HttpServer_test.cc b/include/Third_Lib/muduo/net/http/tests/HttpServer_test.cc new file mode 100644 index 0000000..0ec38fb --- /dev/null +++ b/include/Third_Lib/muduo/net/http/tests/HttpServer_test.cc @@ -0,0 +1,150 @@ +#include "muduo/net/http/HttpServer.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Logging.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +extern char favicon[555]; +bool benchmark = false; + +void onRequest(const HttpRequest& req, HttpResponse* resp) +{ + std::cout << "Headers " << req.methodString() << " " << req.path() << std::endl; + if (!benchmark) + { + const std::map& headers = req.headers(); + for (const auto& header : headers) + { + std::cout << header.first << ": " << header.second << std::endl; + } + } + + if (req.path() == "/") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/html"); + resp->addHeader("Server", "Muduo"); + string now = Timestamp::now().toFormattedString(); + resp->setBody("This is title" + "

Hello

Now is " + now + + ""); + } + else if (req.path() == "/favicon.ico") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("image/png"); + resp->setBody(string(favicon, sizeof favicon)); + } + else if (req.path() == "/hello") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->addHeader("Server", "Muduo"); + resp->setBody("hello, world!\n"); + } + else + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); + } +} + +int main(int argc, char* argv[]) +{ + int numThreads = 0; + if (argc > 1) + { + benchmark = true; + Logger::setLogLevel(Logger::WARN); + numThreads = atoi(argv[1]); + } + EventLoop loop; + HttpServer server(&loop, InetAddress(8000), "dummy"); + server.setHttpCallback(onRequest); + server.setThreadNum(numThreads); + server.start(); + loop.loop(); +} + +char favicon[555] = { + '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA', + '\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R', + '\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10', + '\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF', + 'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X', + 't', 'S', 'o', 'f', 't', 'w', 'a', 'r', + 'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20', + 'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a', + 'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0', + '\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA', + '\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86', + '\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm', + '\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16', + 'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8', + 'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0', + 'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4', + 'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1', + 'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB', + 'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F', + 'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v', + 'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8', + '\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5', + '\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC', + '\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA', + '\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F', + '\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r', + '9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6', + '\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T', + '\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3', + 'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R', + '\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x', + '\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0', + '\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9', + 'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11', + '\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5', + '3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4', + '\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98', + '\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3', + '\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C', + '\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB', + '\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9', + 'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6', + '\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C', + '\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f', + 'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9', + 'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F', + '\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22', + '\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15', + '\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j', + '\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F', + 'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40', + '\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A', + '\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE', + '\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD', + '\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0', + '\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB', + '\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2', + '\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4', + '\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A', + '\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91', + '\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7', + 'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N', + 'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E', + '\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u', + '\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB', + '\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF', + '\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K', + '\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0', + '\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE', + 'B', '\x60', '\x82', +}; diff --git a/include/Third_Lib/muduo/net/inspect/BUILD.bazel b/include/Third_Lib/muduo/net/inspect/BUILD.bazel new file mode 100644 index 0000000..0592e50 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/BUILD.bazel @@ -0,0 +1,9 @@ +cc_library( + name = "inspect", + srcs = glob(["*.cc"]), + hdrs = glob(["*.h"]), + visibility = ["//visibility:public"], + deps = [ + "//muduo/net/http", + ], +) diff --git a/include/Third_Lib/muduo/net/inspect/CMakeLists.txt b/include/Third_Lib/muduo/net/inspect/CMakeLists.txt new file mode 100644 index 0000000..1ce908f --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/CMakeLists.txt @@ -0,0 +1,26 @@ +set(inspect_SRCS + Inspector.cc + PerformanceInspector.cc + ProcessInspector.cc + SystemInspector.cc + ) + +add_library(muduo_inspect ${inspect_SRCS}) +target_link_libraries(muduo_inspect muduo_http) + +if(TCMALLOC_INCLUDE_DIR AND TCMALLOC_LIBRARY) + set_target_properties(muduo_inspect PROPERTIES COMPILE_FLAGS "-DHAVE_TCMALLOC") + target_link_libraries(muduo_inspect tcmalloc_and_profiler) +endif() + +install(TARGETS muduo_inspect DESTINATION lib) +set(HEADERS + Inspector.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/inspect) + +if(MUDUO_BUILD_EXAMPLES) +add_executable(inspector_test tests/Inspector_test.cc) +target_link_libraries(inspector_test muduo_inspect) +endif() + diff --git a/include/Third_Lib/muduo/net/inspect/Inspector.cc b/include/Third_Lib/muduo/net/inspect/Inspector.cc new file mode 100644 index 0000000..894abd3 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/Inspector.cc @@ -0,0 +1,383 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/Inspector.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/inspect/ProcessInspector.h" +#include "muduo/net/inspect/PerformanceInspector.h" +#include "muduo/net/inspect/SystemInspector.h" + +//#include +//#include +//#include +//#include +//#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ +Inspector* g_globalInspector = 0; + +// Looks buggy +std::vector split(const string& str) +{ + std::vector result; + size_t start = 0; + size_t pos = str.find('/'); + while (pos != string::npos) + { + if (pos > start) + { + result.push_back(str.substr(start, pos-start)); + } + start = pos+1; + pos = str.find('/', start); + } + + if (start < str.length()) + { + result.push_back(str.substr(start)); + } + + return result; +} + +} // namespace + +extern char favicon[1743]; + +Inspector::Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name) + : server_(loop, httpAddr, "Inspector:"+name), + processInspector_(new ProcessInspector), + systemInspector_(new SystemInspector) +{ + assert(CurrentThread::isMainThread()); + assert(g_globalInspector == 0); + g_globalInspector = this; + server_.setHttpCallback(std::bind(&Inspector::onRequest, this, _1, _2)); + processInspector_->registerCommands(this); + systemInspector_->registerCommands(this); +#ifdef HAVE_TCMALLOC + performanceInspector_.reset(new PerformanceInspector); + performanceInspector_->registerCommands(this); +#endif + loop->runAfter(0, std::bind(&Inspector::start, this)); // little race condition +} + +Inspector::~Inspector() +{ + assert(CurrentThread::isMainThread()); + g_globalInspector = NULL; +} + +void Inspector::add(const string& module, + const string& command, + const Callback& cb, + const string& help) +{ + MutexLockGuard lock(mutex_); + modules_[module][command] = cb; + helps_[module][command] = help; +} + +void Inspector::remove(const string& module, const string& command) +{ + MutexLockGuard lock(mutex_); + std::map::iterator it = modules_.find(module); + if (it != modules_.end()) + { + it->second.erase(command); + helps_[module].erase(command); + } +} + +void Inspector::start() +{ + server_.start(); +} + +void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) +{ + if (req.path() == "/") + { + string result; + MutexLockGuard lock(mutex_); + for (std::map::const_iterator helpListI = helps_.begin(); + helpListI != helps_.end(); + ++helpListI) + { + const HelpList& list = helpListI->second; + for (const auto& it : list) + { + result += "/"; + result += helpListI->first; + result += "/"; + result += it.first; + size_t len = helpListI->first.size() + it.first.size(); + result += string(len >= 25 ? 1 : 25 - len, ' '); + result += it.second; + result += "\n"; + } + } + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->setBody(result); + } + else + { + std::vector result = split(req.path()); + // boost::split(result, req.path(), boost::is_any_of("/")); + //std::copy(result.begin(), result.end(), std::ostream_iterator(std::cout, ", ")); + //std::cout << "\n"; + bool ok = false; + if (result.size() == 0) + { + LOG_DEBUG << req.path(); + } + else if (result.size() == 1) + { + string module = result[0]; + if (module == "favicon.ico") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("image/png"); + resp->setBody(string(favicon, sizeof favicon)); + + ok = true; + } + else + { + LOG_ERROR << "Unimplemented " << module; + } + } + else + { + string module = result[0]; + MutexLockGuard lock(mutex_); + std::map::const_iterator commListI = modules_.find(module); + if (commListI != modules_.end()) + { + string command = result[1]; + const CommandList& commList = commListI->second; + CommandList::const_iterator it = commList.find(command); + if (it != commList.end()) + { + ArgList args(result.begin()+2, result.end()); + if (it->second) + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + const Callback& cb = it->second; + resp->setBody(cb(req.method(), args)); + ok = true; + } + } + } + + } + + if (!ok) + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + } + //resp->setCloseConnection(true); + } +} + +char favicon[1743] = +{ + '\x89', '\x50', '\x4e', '\x47', '\x0d', '\x0a', '\x1a', '\x0a', '\x00', '\x00', + '\x00', '\x0d', '\x49', '\x48', '\x44', '\x52', '\x00', '\x00', '\x00', '\x10', + '\x00', '\x00', '\x00', '\x10', '\x08', '\x06', '\x00', '\x00', '\x00', '\x1f', + '\xf3', '\xff', '\x61', '\x00', '\x00', '\x00', '\x04', '\x73', '\x42', '\x49', + '\x54', '\x08', '\x08', '\x08', '\x08', '\x7c', '\x08', '\x64', '\x88', '\x00', + '\x00', '\x00', '\x09', '\x70', '\x48', '\x59', '\x73', '\x00', '\x00', '\x0b', + '\x12', '\x00', '\x00', '\x0b', '\x12', '\x01', '\xd2', '\xdd', '\x7e', '\xfc', + '\x00', '\x00', '\x00', '\x1c', '\x74', '\x45', '\x58', '\x74', '\x53', '\x6f', + '\x66', '\x74', '\x77', '\x61', '\x72', '\x65', '\x00', '\x41', '\x64', '\x6f', + '\x62', '\x65', '\x20', '\x46', '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', + '\x6b', '\x73', '\x20', '\x43', '\x53', '\x33', '\x98', '\xd6', '\x46', '\x03', + '\x00', '\x00', '\x00', '\x15', '\x74', '\x45', '\x58', '\x74', '\x43', '\x72', + '\x65', '\x61', '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x54', '\x69', '\x6d', + '\x65', '\x00', '\x32', '\x2f', '\x31', '\x37', '\x2f', '\x30', '\x38', '\x20', + '\x9c', '\xaa', '\x58', '\x00', '\x00', '\x04', '\x11', '\x74', '\x45', '\x58', + '\x74', '\x58', '\x4d', '\x4c', '\x3a', '\x63', '\x6f', '\x6d', '\x2e', '\x61', + '\x64', '\x6f', '\x62', '\x65', '\x2e', '\x78', '\x6d', '\x70', '\x00', '\x3c', + '\x3f', '\x78', '\x70', '\x61', '\x63', '\x6b', '\x65', '\x74', '\x20', '\x62', + '\x65', '\x67', '\x69', '\x6e', '\x3d', '\x22', '\x20', '\x20', '\x20', '\x22', + '\x20', '\x69', '\x64', '\x3d', '\x22', '\x57', '\x35', '\x4d', '\x30', '\x4d', + '\x70', '\x43', '\x65', '\x68', '\x69', '\x48', '\x7a', '\x72', '\x65', '\x53', + '\x7a', '\x4e', '\x54', '\x63', '\x7a', '\x6b', '\x63', '\x39', '\x64', '\x22', + '\x3f', '\x3e', '\x0a', '\x3c', '\x78', '\x3a', '\x78', '\x6d', '\x70', '\x6d', + '\x65', '\x74', '\x61', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', + '\x78', '\x3d', '\x22', '\x61', '\x64', '\x6f', '\x62', '\x65', '\x3a', '\x6e', + '\x73', '\x3a', '\x6d', '\x65', '\x74', '\x61', '\x2f', '\x22', '\x20', '\x78', + '\x3a', '\x78', '\x6d', '\x70', '\x74', '\x6b', '\x3d', '\x22', '\x41', '\x64', + '\x6f', '\x62', '\x65', '\x20', '\x58', '\x4d', '\x50', '\x20', '\x43', '\x6f', + '\x72', '\x65', '\x20', '\x34', '\x2e', '\x31', '\x2d', '\x63', '\x30', '\x33', + '\x34', '\x20', '\x34', '\x36', '\x2e', '\x32', '\x37', '\x32', '\x39', '\x37', + '\x36', '\x2c', '\x20', '\x53', '\x61', '\x74', '\x20', '\x4a', '\x61', '\x6e', + '\x20', '\x32', '\x37', '\x20', '\x32', '\x30', '\x30', '\x37', '\x20', '\x32', + '\x32', '\x3a', '\x31', '\x31', '\x3a', '\x34', '\x31', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x22', '\x3e', '\x0a', '\x20', '\x20', + '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x52', '\x44', '\x46', '\x20', + '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x72', '\x64', '\x66', '\x3d', + '\x22', '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x77', '\x77', + '\x77', '\x2e', '\x77', '\x33', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x31', + '\x39', '\x39', '\x39', '\x2f', '\x30', '\x32', '\x2f', '\x32', '\x32', '\x2d', + '\x72', '\x64', '\x66', '\x2d', '\x73', '\x79', '\x6e', '\x74', '\x61', '\x78', + '\x2d', '\x6e', '\x73', '\x23', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x44', '\x65', + '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', '\x20', + '\x72', '\x64', '\x66', '\x3a', '\x61', '\x62', '\x6f', '\x75', '\x74', '\x3d', + '\x22', '\x22', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', + '\x3a', '\x78', '\x61', '\x70', '\x3d', '\x22', '\x68', '\x74', '\x74', '\x70', + '\x3a', '\x2f', '\x2f', '\x6e', '\x73', '\x2e', '\x61', '\x64', '\x6f', '\x62', + '\x65', '\x2e', '\x63', '\x6f', '\x6d', '\x2f', '\x78', '\x61', '\x70', '\x2f', + '\x31', '\x2e', '\x30', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', + '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', + '\x6f', '\x6c', '\x3e', '\x41', '\x64', '\x6f', '\x62', '\x65', '\x20', '\x46', + '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', '\x6b', '\x73', '\x20', '\x43', + '\x53', '\x33', '\x3c', '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', + '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', '\x6f', '\x6c', '\x3e', + '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', + '\x65', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', '\x30', '\x30', '\x38', + '\x2d', '\x30', '\x32', '\x2d', '\x31', '\x37', '\x54', '\x30', '\x32', '\x3a', + '\x33', '\x36', '\x3a', '\x34', '\x35', '\x5a', '\x3c', '\x2f', '\x78', '\x61', + '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x65', '\x44', '\x61', + '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', + '\x64', '\x69', '\x66', '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', + '\x30', '\x30', '\x38', '\x2d', '\x30', '\x33', '\x2d', '\x32', '\x34', '\x54', + '\x31', '\x39', '\x3a', '\x30', '\x30', '\x3a', '\x34', '\x32', '\x5a', '\x3c', + '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', '\x64', '\x69', '\x66', + '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', + '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', + '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x72', + '\x64', '\x66', '\x3a', '\x44', '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', + '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x72', '\x64', '\x66', '\x3a', '\x61', + '\x62', '\x6f', '\x75', '\x74', '\x3d', '\x22', '\x22', '\x0a', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x64', '\x63', '\x3d', '\x22', + '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x70', '\x75', '\x72', + '\x6c', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x64', '\x63', '\x2f', '\x65', + '\x6c', '\x65', '\x6d', '\x65', '\x6e', '\x74', '\x73', '\x2f', '\x31', '\x2e', + '\x31', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x3c', '\x64', '\x63', '\x3a', '\x66', '\x6f', + '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x69', '\x6d', '\x61', '\x67', '\x65', + '\x2f', '\x70', '\x6e', '\x67', '\x3c', '\x2f', '\x64', '\x63', '\x3a', '\x66', + '\x6f', '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', + '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', + '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', + '\x3a', '\x52', '\x44', '\x46', '\x3e', '\x0a', '\x3c', '\x2f', '\x78', '\x3a', + '\x78', '\x6d', '\x70', '\x6d', '\x65', '\x74', '\x61', '\x3e', '\x0a', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x0a', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x35', '\x1d', '\x52', '\x64', '\x00', '\x00', '\x02', '\x0b', + '\x49', '\x44', '\x41', '\x54', '\x38', '\x8d', '\xa5', '\x93', '\x41', '\x6b', + '\x1a', '\x41', '\x18', '\x86', '\x9f', '\x89', '\x06', '\x23', '\x2e', '\x74', + '\xf5', '\x20', '\x4a', '\x0e', '\x6b', '\x20', '\xe4', '\xe2', '\xa5', '\x78', + '\xc8', '\xa1', '\x78', '\x89', '\x82', '\x17', '\x85', '\x82', '\x82', '\x3d', + '\x26', '\x62', '\x58', '\x72', '\xcd', '\x4f', '\xf1', '\x18', '\x4b', '\x1b', + '\x2f', '\xa5', '\x32', '\xe0', '\xb5', '\x9e', '\x35', '\x1a', '\x58', '\x2f', + '\xe9', '\x0f', '\xe8', '\x65', '\x6d', '\x84', '\xa2', '\x84', '\x2c', '\x0a', + '\x6b', '\x58', '\x62', '\xa7', '\x87', '\x68', '\x68', '\x13', '\xa1', '\xa5', + '\x79', '\xe1', '\x3b', '\x0c', '\xc3', '\xfb', '\xcc', '\x37', '\xef', '\x7c', + '\x23', '\x94', '\x52', '\xbc', '\x44', '\x7e', '\x00', '\x21', '\x04', '\x00', + '\xad', '\x56', '\xcb', '\x18', '\x8f', '\xc7', '\x0d', '\xdb', '\xb6', '\xd3', + '\x8e', '\xe3', '\xf8', '\x83', '\xc1', '\xa0', '\x8a', '\xc7', '\xe3', '\x3f', + '\x12', '\x89', '\x44', '\xb9', '\x5c', '\x2e', '\xf7', '\x56', '\xa6', '\xdf', + '\x0f', '\x15', '\x4a', '\x29', '\x84', '\x10', '\x34', '\x9b', '\xcd', '\x77', + '\x96', '\x65', '\x7d', '\x36', '\x0c', '\x43', '\xe4', '\x72', '\x39', '\xe2', + '\xf1', '\x38', '\xb7', '\xb7', '\xb7', '\xf4', '\xfb', '\x7d', '\x06', '\x83', + '\x01', '\xa9', '\x54', '\xea', '\x43', '\xa5', '\x52', '\x39', '\x7e', '\x0a', + '\x40', '\x29', '\x45', '\xab', '\xd5', '\x32', '\x4e', '\x4f', '\x4f', '\x7f', + '\x4a', '\x29', '\xd5', '\xdd', '\xdd', '\xdd', '\xb3', '\xea', '\xf5', '\x7a', + '\xea', '\xe4', '\xe4', '\x44', '\x49', '\x29', '\xd3', '\x2b', '\xcf', '\xaa', + '\x36', '\x00', '\xc6', '\xe3', '\x71', '\x63', '\x67', '\x67', '\x47', '\xe4', + '\xf3', '\x79', '\x00', '\x3c', '\xcf', '\xa3', '\x50', '\x28', '\xe0', '\xba', + '\x2e', '\x9e', '\xe7', '\x91', '\x4a', '\xa5', '\xd8', '\xdb', '\xdb', '\x63', + '\x34', '\x1a', '\x7d', '\x7c', '\x9a', '\xc1', '\x06', '\x80', '\x6d', '\xdb', + '\xe9', '\x6c', '\x36', '\x8b', '\xcf', '\xe7', '\xc3', '\xf3', '\x3c', '\x5c', + '\xd7', '\x05', '\x60', '\x36', '\x9b', '\xe1', '\xba', '\x2e', '\x8b', '\xc5', + '\x82', '\x4c', '\x26', '\x83', '\x6d', '\xdb', '\xbb', '\x6b', '\x43', '\x74', + '\x1c', '\xc7', '\x1f', '\x8b', '\xc5', '\x00', '\x28', '\x16', '\x8b', '\x8f', + '\x9b', '\xd5', '\x6a', '\x15', '\x00', '\x29', '\x25', '\x9a', '\xa6', '\x31', + '\x9f', '\xcf', '\xc5', '\x5a', '\xc0', '\xd6', '\xd6', '\x96', '\x9a', '\x4c', + '\x26', '\x22', '\x14', '\x0a', '\x21', '\xa5', '\x64', '\x36', '\x9b', '\x51', + '\xad', '\x56', '\xa9', '\xd5', '\x6a', '\x68', '\x9a', '\x06', '\xc0', '\xf5', + '\xf5', '\x35', '\xba', '\xae', '\xdf', '\xaf', '\xbd', '\x82', '\x61', '\x18', + '\xdf', '\x2c', '\xcb', '\x7a', '\x20', '\xfa', '\xfd', '\x04', '\x02', '\x01', + '\x00', '\x34', '\x4d', '\x23', '\x10', '\x08', '\xb0', '\x58', '\x2c', '\xe8', + '\x76', '\xbb', '\x24', '\x12', '\x89', '\x8b', '\xb5', '\x1d', '\x6c', '\x6f', + '\x6f', '\x1f', '\x75', '\x3a', '\x9d', '\x7e', '\x38', '\x1c', '\x26', '\x97', + '\xcb', '\x21', '\x84', '\x40', '\x4a', '\x09', '\xc0', '\xe6', '\xe6', '\x26', + '\xed', '\x76', '\x9b', '\xc9', '\x64', '\xa2', '\xa6', '\xd3', '\xe9', '\x27', + '\x78', '\x98', '\x9b', '\xd5', '\x53', '\x3e', '\xce', '\xc1', '\xf9', '\xf9', + '\xf9', '\xfb', '\xc1', '\x60', '\x70', '\x9c', '\x4c', '\x26', '\xd9', '\xdf', + '\xdf', '\x27', '\x12', '\x89', '\x30', '\x1c', '\x0e', '\xb9', '\xbc', '\xbc', + '\xe4', '\xe6', '\xe6', '\x46', '\xf9', '\x7c', '\xbe', '\x2f', '\xd3', '\xe9', + '\x34', '\x0f', '\x34', '\xea', '\xf5', '\x7a', '\xe5', '\x19', '\x60', '\x19', + '\xd6', '\x9b', '\xd1', '\x68', '\xd4', '\x18', '\x0e', '\x87', '\xbb', '\xf3', + '\xf9', '\x5c', '\xe8', '\xba', '\x7e', '\x6f', '\x18', '\xc6', '\x45', '\x34', + '\x1a', '\x3d', '\x2c', '\x95', '\x4a', '\xdf', '\x4d', '\xd3', '\xbc', '\x02', + '\x5e', '\x03', '\x5f', '\x81', '\x83', '\xb3', '\xb3', '\x33', '\xe7', '\x0f', + '\xc0', '\xdf', '\x64', '\x9a', '\xa6', '\xb1', '\x34', '\xeb', '\x80', '\x03', + '\x1c', '\x6c', '\xfc', '\x93', '\x73', '\xa9', '\x7a', '\xbd', '\x6e', '\x03', + '\x47', '\xcb', '\xa5', '\x0e', '\xbc', '\xe2', '\x7f', '\x7e', '\xa3', '\x69', + '\x9a', '\x87', '\xa6', '\x69', '\xbe', '\x55', '\x4a', '\x3d', '\x64', '\xf0', + '\x12', '\xfd', '\x02', '\x0d', '\x53', '\x06', '\x24', '\x88', '\x3f', '\xe1', + '\x69', '\x00', '\x00', '\x00', '\x00', '\x49', '\x45', '\x4e', '\x44', '\xae', + '\x42', '\x60', '\x82', +}; diff --git a/include/Third_Lib/muduo/net/inspect/Inspector.h b/include/Third_Lib/muduo/net/inspect/Inspector.h new file mode 100644 index 0000000..09041d1 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/Inspector.h @@ -0,0 +1,67 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_INSPECT_INSPECTOR_H +#define MUDUO_NET_INSPECT_INSPECTOR_H + +#include "muduo/base/Mutex.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpServer.h" + +#include + +namespace muduo +{ +namespace net +{ + +class ProcessInspector; +class PerformanceInspector; +class SystemInspector; + +// An internal inspector of the running process, usually a singleton. +// Better to run in a seperated thread, as some method may block for seconds +class Inspector : noncopyable +{ + public: + typedef std::vector ArgList; + typedef std::function Callback; + Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name); + ~Inspector(); + + /// Add a Callback for handling the special uri : /mudule/command + void add(const string& module, + const string& command, + const Callback& cb, + const string& help); + void remove(const string& module, const string& command); + + private: + typedef std::map CommandList; + typedef std::map HelpList; + + void start(); + void onRequest(const HttpRequest& req, HttpResponse* resp); + + HttpServer server_; + std::unique_ptr processInspector_; + std::unique_ptr performanceInspector_; + std::unique_ptr systemInspector_; + MutexLock mutex_; + std::map modules_ GUARDED_BY(mutex_); + std::map helps_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_INSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/PerformanceInspector.cc b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.cc new file mode 100644 index 0000000..a0fb9e9 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.cc @@ -0,0 +1,106 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/PerformanceInspector.h" +#include "muduo/base/FileUtil.h" +#include "muduo/base/LogStream.h" +#include "muduo/base/ProcessInfo.h" + +#include + +#ifdef HAVE_TCMALLOC +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void PerformanceInspector::registerCommands(Inspector* ins) +{ + ins->add("pprof", "heap", PerformanceInspector::heap, "get heap information"); + ins->add("pprof", "growth", PerformanceInspector::growth, "get heap growth information"); + ins->add("pprof", "profile", PerformanceInspector::profile, + "get cpu profiling information. CAUTION: blocking thread for 30 seconds!"); + ins->add("pprof", "cmdline", PerformanceInspector::cmdline, "get command line"); + ins->add("pprof", "memstats", PerformanceInspector::memstats, "get memory stats"); + ins->add("pprof", "memhistogram", PerformanceInspector::memhistogram, "get memory histogram"); + ins->add("pprof", "releasefreememory", PerformanceInspector::releaseFreeMemory, "release free memory"); +} + +string PerformanceInspector::heap(HttpRequest::Method, const Inspector::ArgList&) +{ + std::string result; + MallocExtension::instance()->GetHeapSample(&result); + return string(result.data(), result.size()); +} + +string PerformanceInspector::growth(HttpRequest::Method, const Inspector::ArgList&) +{ + std::string result; + MallocExtension::instance()->GetHeapGrowthStacks(&result); + return string(result.data(), result.size()); +} + +string PerformanceInspector::profile(HttpRequest::Method, const Inspector::ArgList&) +{ + string filename = "/tmp/" + ProcessInfo::procname(); + filename += "."; + filename += ProcessInfo::pidString(); + filename += "."; + filename += Timestamp::now().toString(); + filename += ".profile"; + + string profile; + if (ProfilerStart(filename.c_str())) + { + // FIXME: async + CurrentThread::sleepUsec(30 * 1000 * 1000); + ProfilerStop(); + FileUtil::readFile(filename, 1024*1024, &profile, NULL, NULL); + ::unlink(filename.c_str()); + } + return profile; +} + +string PerformanceInspector::cmdline(HttpRequest::Method, const Inspector::ArgList&) +{ + return ""; +} + +string PerformanceInspector::memstats(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[1024*64]; + MallocExtension::instance()->GetStats(buf, sizeof buf); + return buf; +} + +string PerformanceInspector::memhistogram(HttpRequest::Method, const Inspector::ArgList&) +{ + int blocks = 0; + size_t total = 0; + int histogram[kMallocHistogramSize] = { 0, }; + + MallocExtension::instance()->MallocMemoryStats(&blocks, &total, histogram); + LogStream s; + s << "blocks " << blocks << "\ntotal " << total << "\n"; + for (int i = 0; i < kMallocHistogramSize; ++i) + s << i << " " << histogram[i] << "\n"; + return s.buffer().toString(); +} + +string PerformanceInspector::releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[256]; + snprintf(buf, sizeof buf, "memory release rate: %f\nAll free memory released.\n", + MallocExtension::instance()->GetMemoryReleaseRate()); + MallocExtension::instance()->ReleaseFreeMemory(); + return buf; +} + +#endif diff --git a/include/Third_Lib/muduo/net/inspect/PerformanceInspector.h b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.h new file mode 100644 index 0000000..2416824 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.h @@ -0,0 +1,40 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H +#define MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class PerformanceInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string heap(HttpRequest::Method, const Inspector::ArgList&); + static string growth(HttpRequest::Method, const Inspector::ArgList&); + static string profile(HttpRequest::Method, const Inspector::ArgList&); + static string cmdline(HttpRequest::Method, const Inspector::ArgList&); + static string memstats(HttpRequest::Method, const Inspector::ArgList&); + static string memhistogram(HttpRequest::Method, const Inspector::ArgList&); + static string releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&); + + static string symbol(HttpRequest::Method, const Inspector::ArgList&); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/ProcessInspector.cc b/include/Third_Lib/muduo/net/inspect/ProcessInspector.cc new file mode 100644 index 0000000..d89f0ce --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/ProcessInspector.cc @@ -0,0 +1,239 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/ProcessInspector.h" +#include "muduo/base/FileUtil.h" +#include "muduo/base/ProcessInfo.h" +#include +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace inspect +{ + +string uptime(Timestamp now, Timestamp start, bool showMicroseconds) +{ + char buf[256]; + int64_t age = now.microSecondsSinceEpoch() - start.microSecondsSinceEpoch(); + int seconds = static_cast(age / Timestamp::kMicroSecondsPerSecond); + int days = seconds/86400; + int hours = (seconds % 86400) / 3600; + int minutes = (seconds % 3600) / 60; + if (showMicroseconds) + { + int microseconds = static_cast(age % Timestamp::kMicroSecondsPerSecond); + snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d.%06d", + days, hours, minutes, seconds % 60, microseconds); + } + else + { + snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d", + days, hours, minutes, seconds % 60); + } + return buf; +} + +long getLong(const string& procStatus, const char* key) +{ + long result = 0; + size_t pos = procStatus.find(key); + if (pos != string::npos) + { + result = ::atol(procStatus.c_str() + pos + strlen(key)); + } + return result; +} + +string getProcessName(const string& procStatus) +{ + string result; + size_t pos = procStatus.find("Name:"); + if (pos != string::npos) + { + pos += strlen("Name:"); + while (procStatus[pos] == '\t') + ++pos; + size_t eol = pos; + while (procStatus[eol] != '\n') + ++eol; + result = procStatus.substr(pos, eol-pos); + } + return result; +} + +StringPiece next(StringPiece data) +{ + const char* sp = static_cast(::memchr(data.data(), ' ', data.size())); + if (sp) + { + data.remove_prefix(static_cast(sp+1-data.begin())); + return data; + } + return ""; +} + +ProcessInfo::CpuTime getCpuTime(StringPiece data) +{ + ProcessInfo::CpuTime t; + + for (int i = 0; i < 10; ++i) + { + data = next(data); + } + long utime = strtol(data.data(), NULL, 10); + data = next(data); + long stime = strtol(data.data(), NULL, 10); + const double hz = static_cast(ProcessInfo::clockTicksPerSecond()); + t.userSeconds = static_cast(utime) / hz; + t.systemSeconds = static_cast(stime) / hz; + return t; +} + +int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); + +int stringPrintf(string* out, const char* fmt, ...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + int ret = vsnprintf(buf, sizeof buf, fmt, args); + va_end(args); + out->append(buf); + return ret; +} + +} // namespace inspect +} // namespace muduo + +using namespace muduo::inspect; + +string ProcessInspector::username_ = ProcessInfo::username(); + +void ProcessInspector::registerCommands(Inspector* ins) +{ + ins->add("proc", "overview", ProcessInspector::overview, "print basic overview"); + ins->add("proc", "pid", ProcessInspector::pid, "print pid"); + ins->add("proc", "status", ProcessInspector::procStatus, "print /proc/self/status"); + // ins->add("proc", "opened_files", ProcessInspector::openedFiles, "count /proc/self/fd"); + ins->add("proc", "threads", ProcessInspector::threads, "list /proc/self/task"); +} + +string ProcessInspector::overview(HttpRequest::Method, const Inspector::ArgList&) +{ + string result; + result.reserve(1024); + Timestamp now = Timestamp::now(); + result += "Page generated at "; + result += now.toFormattedString(); + result += " (UTC)\nStarted at "; + result += ProcessInfo::startTime().toFormattedString(); + result += " (UTC), up for "; + result += uptime(now, ProcessInfo::startTime(), true/* show microseconds */); + result += "\n"; + + string procStatus = ProcessInfo::procStatus(); + result += getProcessName(procStatus); + result += " ("; + result += ProcessInfo::exePath(); + result += ") running as "; + result += username_; + result += " on "; + result += ProcessInfo::hostname(); // cache ? + result += "\n"; + + if (ProcessInfo::isDebugBuild()) + { + result += "WARNING: debug build!\n"; + } + + stringPrintf(&result, "pid %d, num of threads %ld, bits %zd\n", + ProcessInfo::pid(), getLong(procStatus, "Threads:"), CHAR_BIT * sizeof(void*)); + + result += "Virtual memory: "; + stringPrintf(&result, "%.3f MiB, ", + static_cast(getLong(procStatus, "VmSize:")) / 1024.0); + + result += "RSS memory: "; + stringPrintf(&result, "%.3f MiB\n", + static_cast(getLong(procStatus, "VmRSS:")) / 1024.0); + + // FIXME: VmData: + + stringPrintf(&result, "Opened files: %d, limit: %d\n", + ProcessInfo::openedFiles(), ProcessInfo::maxOpenFiles()); + + // string procStat = ProcessInfo::procStat(); + + /* + stringPrintf(&result, "ppid %ld\n", getStatField(procStat, 0)); + stringPrintf(&result, "pgid %ld\n", getStatField(procStat, 1)); + */ + + ProcessInfo::CpuTime t = ProcessInfo::cpuTime(); + stringPrintf(&result, "User time: %12.3fs\nSys time: %12.3fs\n", + t.userSeconds, t.systemSeconds); + + // FIXME: add context switches + + return result; +} + +string ProcessInspector::pid(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::pid()); + return buf; +} + +string ProcessInspector::procStatus(HttpRequest::Method, const Inspector::ArgList&) +{ + return ProcessInfo::procStatus(); +} + +string ProcessInspector::openedFiles(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::openedFiles()); + return buf; +} + +string ProcessInspector::threads(HttpRequest::Method, const Inspector::ArgList&) +{ + std::vector threads = ProcessInfo::threads(); + string result = " TID NAME S User Time System Time\n"; + result.reserve(threads.size() * 64); + string stat; + for (pid_t tid : threads) + { + char buf[256]; + snprintf(buf, sizeof buf, "/proc/%d/task/%d/stat", ProcessInfo::pid(), tid); + if (FileUtil::readFile(buf, 65536, &stat) == 0) + { + StringPiece name = ProcessInfo::procname(stat); + const char* rp = name.end(); + assert(*rp == ')'); + const char* state = rp + 2; + *const_cast(rp) = '\0'; // don't do this at home + StringPiece data(stat); + data.remove_prefix(static_cast(state - data.data() + 2)); + ProcessInfo::CpuTime t = getCpuTime(data); + snprintf(buf, sizeof buf, "%5d %-16s %c %12.3f %12.3f\n", + tid, name.data(), *state, t.userSeconds, t.systemSeconds); + result += buf; + } + } + return result; +} + diff --git a/include/Third_Lib/muduo/net/inspect/ProcessInspector.h b/include/Third_Lib/muduo/net/inspect/ProcessInspector.h new file mode 100644 index 0000000..f1df478 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/ProcessInspector.h @@ -0,0 +1,38 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_PROCESSINSPECTOR_H +#define MUDUO_NET_INSPECT_PROCESSINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class ProcessInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string overview(HttpRequest::Method, const Inspector::ArgList&); + static string pid(HttpRequest::Method, const Inspector::ArgList&); + static string procStatus(HttpRequest::Method, const Inspector::ArgList&); + static string openedFiles(HttpRequest::Method, const Inspector::ArgList&); + static string threads(HttpRequest::Method, const Inspector::ArgList&); + + static string username_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_PROCESSINSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/SystemInspector.cc b/include/Third_Lib/muduo/net/inspect/SystemInspector.cc new file mode 100644 index 0000000..fb45e76 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/SystemInspector.cc @@ -0,0 +1,132 @@ +// Copyright 2014, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/SystemInspector.h" +#include "muduo/base/FileUtil.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace inspect +{ +string uptime(Timestamp now, Timestamp start, bool showMicroseconds); +long getLong(const string& content, const char* key); +int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); +} +} + +using namespace muduo::inspect; + +void SystemInspector::registerCommands(Inspector* ins) +{ + ins->add("sys", "overview", SystemInspector::overview, "print system overview"); + ins->add("sys", "loadavg", SystemInspector::loadavg, "print /proc/loadavg"); + ins->add("sys", "version", SystemInspector::version, "print /proc/version"); + ins->add("sys", "cpuinfo", SystemInspector::cpuinfo, "print /proc/cpuinfo"); + ins->add("sys", "meminfo", SystemInspector::meminfo, "print /proc/meminfo"); + ins->add("sys", "stat", SystemInspector::stat, "print /proc/stat"); +} + +string SystemInspector::loadavg(HttpRequest::Method, const Inspector::ArgList&) +{ + string loadavg; + FileUtil::readFile("/proc/loadavg", 65536, &loadavg); + return loadavg; +} + +string SystemInspector::version(HttpRequest::Method, const Inspector::ArgList&) +{ + string version; + FileUtil::readFile("/proc/version", 65536, &version); + return version; +} + +string SystemInspector::cpuinfo(HttpRequest::Method, const Inspector::ArgList&) +{ + string cpuinfo; + FileUtil::readFile("/proc/cpuinfo", 65536, &cpuinfo); + return cpuinfo; +} + +string SystemInspector::meminfo(HttpRequest::Method, const Inspector::ArgList&) +{ + string meminfo; + FileUtil::readFile("/proc/meminfo", 65536, &meminfo); + return meminfo; +} + +string SystemInspector::stat(HttpRequest::Method, const Inspector::ArgList&) +{ + string stat; + FileUtil::readFile("/proc/stat", 65536, &stat); + return stat; +} + +string SystemInspector::overview(HttpRequest::Method, const Inspector::ArgList&) +{ + string result; + result.reserve(1024); + Timestamp now = Timestamp::now(); + result += "Page generated at "; + result += now.toFormattedString(); + result += " (UTC)\n"; + // Hardware and OS + { + struct utsname un; + if (::uname(&un) == 0) + { + stringPrintf(&result, "Hostname: %s\n", un.nodename); + stringPrintf(&result, "Machine: %s\n", un.machine); + stringPrintf(&result, "OS: %s %s %s\n", un.sysname, un.release, un.version); + } + } + string stat; + FileUtil::readFile("/proc/stat", 65536, &stat); + Timestamp bootTime(Timestamp::kMicroSecondsPerSecond * getLong(stat, "btime ")); + result += "Boot time: "; + result += bootTime.toFormattedString(false /* show microseconds */); + result += " (UTC)\n"; + result += "Up time: "; + result += uptime(now, bootTime, false /* show microseconds */); + result += "\n"; + + // CPU load + { + string loadavg; + FileUtil::readFile("/proc/loadavg", 65536, &loadavg); + stringPrintf(&result, "Processes created: %ld\n", getLong(stat, "processes ")); + stringPrintf(&result, "Loadavg: %s\n", loadavg.c_str()); + } + + // Memory + { + string meminfo; + FileUtil::readFile("/proc/meminfo", 65536, &meminfo); + long total_kb = getLong(meminfo, "MemTotal:"); + long free_kb = getLong(meminfo, "MemFree:"); + long buffers_kb = getLong(meminfo, "Buffers:"); + long cached_kb = getLong(meminfo, "Cached:"); + + stringPrintf(&result, "Total Memory: %6ld MiB\n", total_kb / 1024); + stringPrintf(&result, "Free Memory: %6ld MiB\n", free_kb / 1024); + stringPrintf(&result, "Buffers: %6ld MiB\n", buffers_kb / 1024); + stringPrintf(&result, "Cached: %6ld MiB\n", cached_kb / 1024); + stringPrintf(&result, "Real Used: %6ld MiB\n", (total_kb - free_kb - buffers_kb - cached_kb) / 1024); + stringPrintf(&result, "Real Free: %6ld MiB\n", (free_kb + buffers_kb + cached_kb) / 1024); + + // Swap + } + // Disk + // Network + return result; +} diff --git a/include/Third_Lib/muduo/net/inspect/SystemInspector.h b/include/Third_Lib/muduo/net/inspect/SystemInspector.h new file mode 100644 index 0000000..8f2a604 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/SystemInspector.h @@ -0,0 +1,37 @@ +// Copyright 2014, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H +#define MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class SystemInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string overview(HttpRequest::Method, const Inspector::ArgList&); + static string loadavg(HttpRequest::Method, const Inspector::ArgList&); + static string version(HttpRequest::Method, const Inspector::ArgList&); + static string cpuinfo(HttpRequest::Method, const Inspector::ArgList&); + static string meminfo(HttpRequest::Method, const Inspector::ArgList&); + static string stat(HttpRequest::Method, const Inspector::ArgList&); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/tests/BUILD.bazel b/include/Third_Lib/muduo/net/inspect/tests/BUILD.bazel new file mode 100644 index 0000000..e7f0ca7 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/tests/BUILD.bazel @@ -0,0 +1,7 @@ +cc_binary( + name = "inspector", + srcs = ["Inspector_test.cc"], + deps = [ + "//muduo/net/inspect", + ], +) diff --git a/include/Third_Lib/muduo/net/inspect/tests/Inspector_test.cc b/include/Third_Lib/muduo/net/inspect/tests/Inspector_test.cc new file mode 100644 index 0000000..20025ff --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/tests/Inspector_test.cc @@ -0,0 +1,15 @@ +#include "muduo/net/inspect/Inspector.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + EventLoop loop; + EventLoopThread t; + Inspector ins(t.startLoop(), InetAddress(12345), "test"); + loop.loop(); +} + diff --git a/include/Third_Lib/muduo/net/poller/DefaultPoller.cc b/include/Third_Lib/muduo/net/poller/DefaultPoller.cc new file mode 100644 index 0000000..5ea0d03 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/DefaultPoller.cc @@ -0,0 +1,27 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Poller.h" +#include "muduo/net/poller/PollPoller.h" +#include "muduo/net/poller/EPollPoller.h" + +#include + +using namespace muduo::net; + +Poller* Poller::newDefaultPoller(EventLoop* loop) +{ + if (::getenv("MUDUO_USE_POLL")) + { + return new PollPoller(loop); + } + else + { + return new EPollPoller(loop); + } +} diff --git a/include/Third_Lib/muduo/net/poller/EPollPoller.cc b/include/Third_Lib/muduo/net/poller/EPollPoller.cc new file mode 100644 index 0000000..b2f913a --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/EPollPoller.cc @@ -0,0 +1,208 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/poller/EPollPoller.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" + +#include +#include +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +// On Linux, the constants of poll(2) and epoll(4) +// are expected to be the same. +static_assert(EPOLLIN == POLLIN, "epoll uses same flag values as poll"); +static_assert(EPOLLPRI == POLLPRI, "epoll uses same flag values as poll"); +static_assert(EPOLLOUT == POLLOUT, "epoll uses same flag values as poll"); +static_assert(EPOLLRDHUP == POLLRDHUP, "epoll uses same flag values as poll"); +static_assert(EPOLLERR == POLLERR, "epoll uses same flag values as poll"); +static_assert(EPOLLHUP == POLLHUP, "epoll uses same flag values as poll"); + +namespace +{ +const int kNew = -1; +const int kAdded = 1; +const int kDeleted = 2; +} + +EPollPoller::EPollPoller(EventLoop* loop) + : Poller(loop), + epollfd_(::epoll_create1(EPOLL_CLOEXEC)), + events_(kInitEventListSize) +{ + if (epollfd_ < 0) + { + LOG_SYSFATAL << "EPollPoller::EPollPoller"; + } +} + +EPollPoller::~EPollPoller() +{ + ::close(epollfd_); +} + +Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) +{ + LOG_TRACE << "fd total count " << channels_.size(); + int numEvents = ::epoll_wait(epollfd_, + &*events_.begin(), + static_cast(events_.size()), + timeoutMs); + int savedErrno = errno; + Timestamp now(Timestamp::now()); + if (numEvents > 0) + { + LOG_TRACE << numEvents << " events happened"; + fillActiveChannels(numEvents, activeChannels); + if (implicit_cast(numEvents) == events_.size()) + { + events_.resize(events_.size()*2); + } + } + else if (numEvents == 0) + { + LOG_TRACE << "nothing happened"; + } + else + { + // error happens, log uncommon ones + if (savedErrno != EINTR) + { + errno = savedErrno; + LOG_SYSERR << "EPollPoller::poll()"; + } + } + return now; +} + +void EPollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const +{ + assert(implicit_cast(numEvents) <= events_.size()); + for (int i = 0; i < numEvents; ++i) + { + Channel* channel = static_cast(events_[i].data.ptr); +#ifndef NDEBUG + int fd = channel->fd(); + ChannelMap::const_iterator it = channels_.find(fd); + assert(it != channels_.end()); + assert(it->second == channel); +#endif + channel->set_revents(events_[i].events); + activeChannels->push_back(channel); + } +} + +void EPollPoller::updateChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + const int index = channel->index(); + LOG_TRACE << "fd = " << channel->fd() + << " events = " << channel->events() << " index = " << index; + if (index == kNew || index == kDeleted) + { + // a new one, add with EPOLL_CTL_ADD + int fd = channel->fd(); + if (index == kNew) + { + assert(channels_.find(fd) == channels_.end()); + channels_[fd] = channel; + } + else // index == kDeleted + { + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + } + + channel->set_index(kAdded); + update(EPOLL_CTL_ADD, channel); + } + else + { + // update existing one with EPOLL_CTL_MOD/DEL + int fd = channel->fd(); + (void)fd; + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(index == kAdded); + if (channel->isNoneEvent()) + { + update(EPOLL_CTL_DEL, channel); + channel->set_index(kDeleted); + } + else + { + update(EPOLL_CTL_MOD, channel); + } + } +} + +void EPollPoller::removeChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + int fd = channel->fd(); + LOG_TRACE << "fd = " << fd; + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(channel->isNoneEvent()); + int index = channel->index(); + assert(index == kAdded || index == kDeleted); + size_t n = channels_.erase(fd); + (void)n; + assert(n == 1); + + if (index == kAdded) + { + update(EPOLL_CTL_DEL, channel); + } + channel->set_index(kNew); +} + +void EPollPoller::update(int operation, Channel* channel) +{ + struct epoll_event event; + memZero(&event, sizeof event); + event.events = channel->events(); + event.data.ptr = channel; + int fd = channel->fd(); + LOG_TRACE << "epoll_ctl op = " << operationToString(operation) + << " fd = " << fd << " event = { " << channel->eventsToString() << " }"; + if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) + { + if (operation == EPOLL_CTL_DEL) + { + LOG_SYSERR << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; + } + else + { + LOG_SYSFATAL << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; + } + } +} + +const char* EPollPoller::operationToString(int op) +{ + switch (op) + { + case EPOLL_CTL_ADD: + return "ADD"; + case EPOLL_CTL_DEL: + return "DEL"; + case EPOLL_CTL_MOD: + return "MOD"; + default: + assert(false && "ERROR op"); + return "Unknown Operation"; + } +} diff --git a/include/Third_Lib/muduo/net/poller/EPollPoller.h b/include/Third_Lib/muduo/net/poller/EPollPoller.h new file mode 100644 index 0000000..c112f18 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/EPollPoller.h @@ -0,0 +1,55 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H +#define MUDUO_NET_POLLER_EPOLLPOLLER_H + +#include "muduo/net/Poller.h" + +#include + +struct epoll_event; + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with epoll(4). +/// +class EPollPoller : public Poller +{ + public: + EPollPoller(EventLoop* loop); + ~EPollPoller() override; + + Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; + void updateChannel(Channel* channel) override; + void removeChannel(Channel* channel) override; + + private: + static const int kInitEventListSize = 16; + + static const char* operationToString(int op); + + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; + void update(int operation, Channel* channel); + + typedef std::vector EventList; + + int epollfd_; + EventList events_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_POLLER_EPOLLPOLLER_H diff --git a/include/Third_Lib/muduo/net/poller/PollPoller.cc b/include/Third_Lib/muduo/net/poller/PollPoller.cc new file mode 100644 index 0000000..7933079 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/PollPoller.cc @@ -0,0 +1,141 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/poller/PollPoller.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Types.h" +#include "muduo/net/Channel.h" + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +PollPoller::PollPoller(EventLoop* loop) + : Poller(loop) +{ +} + +PollPoller::~PollPoller() = default; + +Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) +{ + // XXX pollfds_ shouldn't change + int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); + int savedErrno = errno; + Timestamp now(Timestamp::now()); + if (numEvents > 0) + { + LOG_TRACE << numEvents << " events happened"; + fillActiveChannels(numEvents, activeChannels); + } + else if (numEvents == 0) + { + LOG_TRACE << " nothing happened"; + } + else + { + if (savedErrno != EINTR) + { + errno = savedErrno; + LOG_SYSERR << "PollPoller::poll()"; + } + } + return now; +} + +void PollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const +{ + for (PollFdList::const_iterator pfd = pollfds_.begin(); + pfd != pollfds_.end() && numEvents > 0; ++pfd) + { + if (pfd->revents > 0) + { + --numEvents; + ChannelMap::const_iterator ch = channels_.find(pfd->fd); + assert(ch != channels_.end()); + Channel* channel = ch->second; + assert(channel->fd() == pfd->fd); + channel->set_revents(pfd->revents); + // pfd->revents = 0; + activeChannels->push_back(channel); + } + } +} + +void PollPoller::updateChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); + if (channel->index() < 0) + { + // a new one, add to pollfds_ + assert(channels_.find(channel->fd()) == channels_.end()); + struct pollfd pfd; + pfd.fd = channel->fd(); + pfd.events = static_cast(channel->events()); + pfd.revents = 0; + pollfds_.push_back(pfd); + int idx = static_cast(pollfds_.size())-1; + channel->set_index(idx); + channels_[pfd.fd] = channel; + } + else + { + // update existing one + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + struct pollfd& pfd = pollfds_[idx]; + assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); + pfd.fd = channel->fd(); + pfd.events = static_cast(channel->events()); + pfd.revents = 0; + if (channel->isNoneEvent()) + { + // ignore this pollfd + pfd.fd = -channel->fd()-1; + } + } +} + +void PollPoller::removeChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd(); + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + assert(channel->isNoneEvent()); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + const struct pollfd& pfd = pollfds_[idx]; (void)pfd; + assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); + size_t n = channels_.erase(channel->fd()); + assert(n == 1); (void)n; + if (implicit_cast(idx) == pollfds_.size()-1) + { + pollfds_.pop_back(); + } + else + { + int channelAtEnd = pollfds_.back().fd; + iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); + if (channelAtEnd < 0) + { + channelAtEnd = -channelAtEnd-1; + } + channels_[channelAtEnd]->set_index(idx); + pollfds_.pop_back(); + } +} + diff --git a/include/Third_Lib/muduo/net/poller/PollPoller.h b/include/Third_Lib/muduo/net/poller/PollPoller.h new file mode 100644 index 0000000..4657534 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/PollPoller.h @@ -0,0 +1,49 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_POLLPOLLER_H +#define MUDUO_NET_POLLER_POLLPOLLER_H + +#include "muduo/net/Poller.h" + +#include + +struct pollfd; + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with poll(2). +/// +class PollPoller : public Poller +{ + public: + + PollPoller(EventLoop* loop); + ~PollPoller() override; + + Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; + void updateChannel(Channel* channel) override; + void removeChannel(Channel* channel) override; + + private: + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; + + typedef std::vector PollFdList; + PollFdList pollfds_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_POLLER_POLLPOLLER_H diff --git a/include/Third_Lib/muduo/net/protobuf/BufferStream.h b/include/Third_Lib/muduo/net/protobuf/BufferStream.h new file mode 100644 index 0000000..322bc44 --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/BufferStream.h @@ -0,0 +1,56 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. +#pragma once +#include "muduo/net/Buffer.h" +#include +namespace muduo +{ +namespace net +{ + +// FIXME: +// class BufferInputStream : google::protobuf::io::ZeroCopyInputStream +// { +// }; + +class BufferOutputStream : public google::protobuf::io::ZeroCopyOutputStream +{ + public: + BufferOutputStream(Buffer* buf) + : buffer_(CHECK_NOTNULL(buf)), + originalSize_(buffer_->readableBytes()) + { + } + + virtual bool Next(void** data, int* size) // override + { + buffer_->ensureWritableBytes(4096); + *data = buffer_->beginWrite(); + *size = static_cast(buffer_->writableBytes()); + buffer_->hasWritten(*size); + return true; + } + + virtual void BackUp(int count) // override + { + buffer_->unwrite(count); + } + + virtual int64_t ByteCount() const // override + { + return buffer_->readableBytes() - originalSize_; + } + + private: + Buffer* buffer_; + size_t originalSize_; +}; + +} +} diff --git a/include/Third_Lib/muduo/net/protobuf/CMakeLists.txt b/include/Third_Lib/muduo/net/protobuf/CMakeLists.txt new file mode 100644 index 0000000..a7e49d9 --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(muduo_protobuf_codec ProtobufCodecLite.cc) +set_target_properties(muduo_protobuf_codec PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +target_link_libraries(muduo_protobuf_codec muduo_net protobuf z) + +#add_library(muduo_protobuf_codec_cpp11 ProtobufCodecLite.cc) +#set_target_properties(muduo_protobuf_codec_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") +#target_link_libraries(muduo_protobuf_codec_cpp11 muduo_net_cpp11 protobuf z) + + +install(TARGETS muduo_protobuf_codec DESTINATION lib) +#install(TARGETS muduo_protobuf_codec_cpp11 DESTINATION lib) + +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION include/muduo/net/protobuf) + diff --git a/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.cc b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.cc new file mode 100644 index 0000000..9d406ee --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.cc @@ -0,0 +1,243 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protobuf/ProtobufCodecLite.h" +// #include + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/TcpConnection.h" +#include "muduo/net/protorpc/google-inl.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + int ProtobufVersionCheck() + { + GOOGLE_PROTOBUF_VERIFY_VERSION; + return 0; + } + int __attribute__ ((unused)) dummy = ProtobufVersionCheck(); +} + +void ProtobufCodecLite::send(const TcpConnectionPtr& conn, + const ::google::protobuf::Message& message) +{ + // FIXME: serialize to TcpConnection::outputBuffer() + muduo::net::Buffer buf; + fillEmptyBuffer(&buf, message); + conn->send(&buf); +} + +void ProtobufCodecLite::fillEmptyBuffer(muduo::net::Buffer* buf, + const google::protobuf::Message& message) +{ + assert(buf->readableBytes() == 0); + // FIXME: can we move serialization & checksum to other thread? + buf->append(tag_); + + int byte_size = serializeToBuffer(message, buf); + + int32_t checkSum = checksum(buf->peek(), static_cast(buf->readableBytes())); + buf->appendInt32(checkSum); + assert(buf->readableBytes() == tag_.size() + byte_size + kChecksumLen); (void) byte_size; + int32_t len = sockets::hostToNetwork32(static_cast(buf->readableBytes())); + buf->prepend(&len, sizeof len); +} + +void ProtobufCodecLite::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + while (buf->readableBytes() >= static_cast(kMinMessageLen+kHeaderLen)) + { + const int32_t len = buf->peekInt32(); + if (len > kMaxMessageLen || len < kMinMessageLen) + { + errorCallback_(conn, buf, receiveTime, kInvalidLength); + break; + } + else if (buf->readableBytes() >= implicit_cast(kHeaderLen+len)) + { + if (rawCb_ && !rawCb_(conn, StringPiece(buf->peek(), kHeaderLen+len), receiveTime)) + { + buf->retrieve(kHeaderLen+len); + continue; + } + MessagePtr message(prototype_->New()); + // FIXME: can we move deserialization & callback to other thread? + ErrorCode errorCode = parse(buf->peek()+kHeaderLen, len, message.get()); + if (errorCode == kNoError) + { + // FIXME: try { } catch (...) { } + messageCallback_(conn, message, receiveTime); + buf->retrieve(kHeaderLen+len); + } + else + { + errorCallback_(conn, buf, receiveTime, errorCode); + break; + } + } + else + { + break; + } + } +} + +bool ProtobufCodecLite::parseFromBuffer(StringPiece buf, google::protobuf::Message* message) +{ + return message->ParseFromArray(buf.data(), buf.size()); +} + +int ProtobufCodecLite::serializeToBuffer(const google::protobuf::Message& message, Buffer* buf) +{ + // TODO: use BufferOutputStream + // BufferOutputStream os(buf); + // message.SerializeToZeroCopyStream(&os); + // return static_cast(os.ByteCount()); + + // code copied from MessageLite::SerializeToArray() and MessageLite::SerializePartialToArray(). + GOOGLE_DCHECK(message.IsInitialized()) << InitializationErrorMessage("serialize", message); + + /** + * 'ByteSize()' of message is deprecated in Protocol Buffers v3.4.0 firstly. But, till to v3.11.0, it just getting start to be marked by '__attribute__((deprecated()))'. + * So, here, v3.9.2 is selected as maximum version using 'ByteSize()' to avoid potential effect for previous muduo code/projects as far as possible. + * Note: All information above just INFER from + * 1) https://github.com/protocolbuffers/protobuf/releases/tag/v3.4.0 + * 2) MACRO in file 'include/google/protobuf/port_def.inc'. eg. '#define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))'. + * In addition, usage of 'ToIntSize()' comes from Impl of ByteSize() in new version's Protocol Buffers. + */ + + #if GOOGLE_PROTOBUF_VERSION > 3009002 + int byte_size = google::protobuf::internal::ToIntSize(message.ByteSizeLong()); + #else + int byte_size = message.ByteSize(); + #endif + buf->ensureWritableBytes(byte_size + kChecksumLen); + + uint8_t* start = reinterpret_cast(buf->beginWrite()); + uint8_t* end = message.SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) + { + #if GOOGLE_PROTOBUF_VERSION > 3009002 + ByteSizeConsistencyError(byte_size, google::protobuf::internal::ToIntSize(message.ByteSizeLong()), static_cast(end - start)); + #else + ByteSizeConsistencyError(byte_size, message.ByteSize(), static_cast(end - start)); + #endif + } + buf->hasWritten(byte_size); + return byte_size; +} + +namespace +{ + const string kNoErrorStr = "NoError"; + const string kInvalidLengthStr = "InvalidLength"; + const string kCheckSumErrorStr = "CheckSumError"; + const string kInvalidNameLenStr = "InvalidNameLen"; + const string kUnknownMessageTypeStr = "UnknownMessageType"; + const string kParseErrorStr = "ParseError"; + const string kUnknownErrorStr = "UnknownError"; +} + +const string& ProtobufCodecLite::errorCodeToString(ErrorCode errorCode) +{ + switch (errorCode) + { + case kNoError: + return kNoErrorStr; + case kInvalidLength: + return kInvalidLengthStr; + case kCheckSumError: + return kCheckSumErrorStr; + case kInvalidNameLen: + return kInvalidNameLenStr; + case kUnknownMessageType: + return kUnknownMessageTypeStr; + case kParseError: + return kParseErrorStr; + default: + return kUnknownErrorStr; + } +} + +void ProtobufCodecLite::defaultErrorCallback(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp, + ErrorCode errorCode) +{ + LOG_ERROR << "ProtobufCodecLite::defaultErrorCallback - " << errorCodeToString(errorCode); + if (conn && conn->connected()) + { + conn->shutdown(); + } +} + +int32_t ProtobufCodecLite::asInt32(const char* buf) +{ + int32_t be32 = 0; + ::memcpy(&be32, buf, sizeof(be32)); + return sockets::networkToHost32(be32); +} + +int32_t ProtobufCodecLite::checksum(const void* buf, int len) +{ + return static_cast( + ::adler32(1, static_cast(buf), len)); +} + +bool ProtobufCodecLite::validateChecksum(const char* buf, int len) +{ + // check sum + int32_t expectedCheckSum = asInt32(buf + len - kChecksumLen); + int32_t checkSum = checksum(buf, len - kChecksumLen); + return checkSum == expectedCheckSum; +} + +ProtobufCodecLite::ErrorCode ProtobufCodecLite::parse(const char* buf, + int len, + ::google::protobuf::Message* message) +{ + ErrorCode error = kNoError; + + if (validateChecksum(buf, len)) + { + if (memcmp(buf, tag_.data(), tag_.size()) == 0) + { + // parse from buffer + const char* data = buf + tag_.size(); + int32_t dataLen = len - kChecksumLen - static_cast(tag_.size()); + if (parseFromBuffer(StringPiece(data, dataLen), message)) + { + error = kNoError; + } + else + { + error = kParseError; + } + } + else + { + error = kUnknownMessageType; + } + } + else + { + error = kCheckSumError; + } + + return error; +} + diff --git a/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.h b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.h new file mode 100644 index 0000000..134ee7b --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.h @@ -0,0 +1,192 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +// For Protobuf codec supporting multiple message types, check +// examples/protobuf/codec + +#ifndef MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H +#define MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" + +#include +#include + +namespace google +{ +namespace protobuf +{ +class Message; +} +} + +namespace muduo +{ +namespace net +{ + +typedef std::shared_ptr MessagePtr; + +// wire format +// +// Field Length Content +// +// size 4-byte M+N+4 +// tag M-byte could be "RPC0", etc. +// payload N-byte +// checksum 4-byte adler32 of tag+payload +// +// This is an internal class, you should use ProtobufCodecT instead. +class ProtobufCodecLite : noncopyable +{ + public: + const static int kHeaderLen = sizeof(int32_t); + const static int kChecksumLen = sizeof(int32_t); + const static int kMaxMessageLen = 64*1024*1024; // same as codec_stream.h kDefaultTotalBytesLimit + + enum ErrorCode + { + kNoError = 0, + kInvalidLength, + kCheckSumError, + kInvalidNameLen, + kUnknownMessageType, + kParseError, + }; + + // return false to stop parsing protobuf message + typedef std::function RawMessageCallback; + + typedef std::function ProtobufMessageCallback; + + typedef std::function ErrorCallback; + + ProtobufCodecLite(const ::google::protobuf::Message* prototype, + StringPiece tagArg, + const ProtobufMessageCallback& messageCb, + const RawMessageCallback& rawCb = RawMessageCallback(), + const ErrorCallback& errorCb = defaultErrorCallback) + : prototype_(prototype), + tag_(tagArg.as_string()), + messageCallback_(messageCb), + rawCb_(rawCb), + errorCallback_(errorCb), + kMinMessageLen(tagArg.size() + kChecksumLen) + { + } + + virtual ~ProtobufCodecLite() = default; + + const string& tag() const { return tag_; } + + void send(const TcpConnectionPtr& conn, + const ::google::protobuf::Message& message); + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + + virtual bool parseFromBuffer(StringPiece buf, google::protobuf::Message* message); + virtual int serializeToBuffer(const google::protobuf::Message& message, Buffer* buf); + + static const string& errorCodeToString(ErrorCode errorCode); + + // public for unit tests + ErrorCode parse(const char* buf, int len, ::google::protobuf::Message* message); + void fillEmptyBuffer(muduo::net::Buffer* buf, const google::protobuf::Message& message); + + static int32_t checksum(const void* buf, int len); + static bool validateChecksum(const char* buf, int len); + static int32_t asInt32(const char* buf); + static void defaultErrorCallback(const TcpConnectionPtr&, + Buffer*, + Timestamp, + ErrorCode); + + private: + const ::google::protobuf::Message* prototype_; + const string tag_; + ProtobufMessageCallback messageCallback_; + RawMessageCallback rawCb_; + ErrorCallback errorCallback_; + const int kMinMessageLen; +}; + +template // TAG must be a variable with external linkage, not a string literal +class ProtobufCodecLiteT +{ + static_assert(std::is_base_of::value, "CODEC should be derived from ProtobufCodecLite"); + public: + typedef std::shared_ptr ConcreteMessagePtr; + typedef std::function ProtobufMessageCallback; + typedef ProtobufCodecLite::RawMessageCallback RawMessageCallback; + typedef ProtobufCodecLite::ErrorCallback ErrorCallback; + + explicit ProtobufCodecLiteT(const ProtobufMessageCallback& messageCb, + const RawMessageCallback& rawCb = RawMessageCallback(), + const ErrorCallback& errorCb = ProtobufCodecLite::defaultErrorCallback) + : messageCallback_(messageCb), + codec_(&MSG::default_instance(), + TAG, + std::bind(&ProtobufCodecLiteT::onRpcMessage, this, _1, _2, _3), + rawCb, + errorCb) + { + } + + const string& tag() const { return codec_.tag(); } + + void send(const TcpConnectionPtr& conn, + const MSG& message) + { + codec_.send(conn, message); + } + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) + { + codec_.onMessage(conn, buf, receiveTime); + } + + // internal + void onRpcMessage(const TcpConnectionPtr& conn, + const MessagePtr& message, + Timestamp receiveTime) + { + messageCallback_(conn, ::muduo::down_pointer_cast(message), receiveTime); + } + + void fillEmptyBuffer(muduo::net::Buffer* buf, const MSG& message) + { + codec_.fillEmptyBuffer(buf, message); + } + + private: + ProtobufMessageCallback messageCallback_; + CODEC codec_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H diff --git a/include/Third_Lib/muduo/net/protorpc/CMakeLists.txt b/include/Third_Lib/muduo/net/protorpc/CMakeLists.txt new file mode 100644 index 0000000..1e5f153 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/CMakeLists.txt @@ -0,0 +1,42 @@ +add_custom_command(OUTPUT rpc.pb.cc rpc.pb.h + COMMAND protoc + ARGS --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/rpc.proto -I${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS rpc.proto + VERBATIM ) + +set_source_files_properties(rpc.pb.cc PROPERTIES COMPILE_FLAGS "-Wno-conversion") +include_directories(${PROJECT_BINARY_DIR}) + +add_library(muduo_protorpc_wire rpc.pb.cc RpcCodec.cc) +set_target_properties(muduo_protorpc_wire PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") + +#add_library(muduo_protorpc_wire_cpp11 rpc.pb.cc RpcCodec.cc) +#set_target_properties(muduo_protorpc_wire_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") + +if(MUDUO_BUILD_EXAMPLES) +add_executable(protobuf_rpc_wire_test RpcCodec_test.cc) +target_link_libraries(protobuf_rpc_wire_test muduo_protorpc_wire muduo_protobuf_codec) +set_target_properties(protobuf_rpc_wire_test PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +endif() + +add_library(muduo_protorpc RpcChannel.cc RpcServer.cc) +set_target_properties(muduo_protorpc PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +target_link_libraries(muduo_protorpc muduo_protorpc_wire muduo_protobuf_codec muduo_net protobuf z) + +if(TCMALLOC_LIBRARY) + target_link_libraries(muduo_protorpc tcmalloc_and_profiler) +endif() + +install(TARGETS muduo_protorpc_wire muduo_protorpc DESTINATION lib) +#install(TARGETS muduo_protorpc_wire_cpp11 DESTINATION lib) + +set(HEADERS + RpcCodec.h + RpcChannel.h + RpcServer.h + rpc.proto + rpcservice.proto + ${PROJECT_BINARY_DIR}/muduo/net/protorpc/rpc.pb.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/protorpc) + diff --git a/include/Third_Lib/muduo/net/protorpc/README b/include/Third_Lib/muduo/net/protorpc/README new file mode 100644 index 0000000..0db4c85 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/README @@ -0,0 +1,5 @@ +This is an proof of concept implementation of Google Protobuf RPC using muduo. +The object lifetime management is for from ideal and doesn't follow the usual +muduo approach. + +Please consider using http://github.com/chenshuo/muduo-protorpc instead. diff --git a/include/Third_Lib/muduo/net/protorpc/RpcChannel.cc b/include/Third_Lib/muduo/net/protorpc/RpcChannel.cc new file mode 100644 index 0000000..d18e081 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcChannel.cc @@ -0,0 +1,184 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcChannel.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/protorpc/rpc.pb.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +RpcChannel::RpcChannel() + : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), + services_(NULL) +{ + LOG_INFO << "RpcChannel::ctor - " << this; +} + +RpcChannel::RpcChannel(const TcpConnectionPtr& conn) + : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), + conn_(conn), + services_(NULL) +{ + LOG_INFO << "RpcChannel::ctor - " << this; +} + +RpcChannel::~RpcChannel() +{ + LOG_INFO << "RpcChannel::dtor - " << this; + for (const auto& outstanding : outstandings_) + { + OutstandingCall out = outstanding.second; + delete out.response; + delete out.done; + } +} + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). +void RpcChannel::CallMethod(const ::google::protobuf::MethodDescriptor* method, + google::protobuf::RpcController* controller, + const ::google::protobuf::Message* request, + ::google::protobuf::Message* response, + ::google::protobuf::Closure* done) +{ + RpcMessage message; + message.set_type(REQUEST); + int64_t id = id_.incrementAndGet(); + message.set_id(id); + message.set_service(method->service()->full_name()); + message.set_method(method->name()); + message.set_request(request->SerializeAsString()); // FIXME: error check + + OutstandingCall out = { response, done }; + { + MutexLockGuard lock(mutex_); + outstandings_[id] = out; + } + codec_.send(conn_, message); +} + +void RpcChannel::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + codec_.onMessage(conn, buf, receiveTime); +} + +void RpcChannel::onRpcMessage(const TcpConnectionPtr& conn, + const RpcMessagePtr& messagePtr, + Timestamp receiveTime) +{ + assert(conn == conn_); + //printf("%s\n", message.DebugString().c_str()); + RpcMessage& message = *messagePtr; + if (message.type() == RESPONSE) + { + int64_t id = message.id(); + assert(message.has_response() || message.has_error()); + + OutstandingCall out = { NULL, NULL }; + + { + MutexLockGuard lock(mutex_); + std::map::iterator it = outstandings_.find(id); + if (it != outstandings_.end()) + { + out = it->second; + outstandings_.erase(it); + } + } + + if (out.response) + { + std::unique_ptr d(out.response); + if (message.has_response()) + { + out.response->ParseFromString(message.response()); + } + if (out.done) + { + out.done->Run(); + } + } + } + else if (message.type() == REQUEST) + { + // FIXME: extract to a function + ErrorCode error = WRONG_PROTO; + if (services_) + { + std::map::const_iterator it = services_->find(message.service()); + if (it != services_->end()) + { + google::protobuf::Service* service = it->second; + assert(service != NULL); + const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); + const google::protobuf::MethodDescriptor* method + = desc->FindMethodByName(message.method()); + if (method) + { + std::unique_ptr request(service->GetRequestPrototype(method).New()); + if (request->ParseFromString(message.request())) + { + google::protobuf::Message* response = service->GetResponsePrototype(method).New(); + // response is deleted in doneCallback + int64_t id = message.id(); + service->CallMethod(method, NULL, get_pointer(request), response, + NewCallback(this, &RpcChannel::doneCallback, response, id)); + error = NO_ERROR; + } + else + { + error = INVALID_REQUEST; + } + } + else + { + error = NO_METHOD; + } + } + else + { + error = NO_SERVICE; + } + } + else + { + error = NO_SERVICE; + } + if (error != NO_ERROR) + { + RpcMessage response; + response.set_type(RESPONSE); + response.set_id(message.id()); + response.set_error(error); + codec_.send(conn_, response); + } + } + else if (message.type() == ERROR) + { + } +} + +void RpcChannel::doneCallback(::google::protobuf::Message* response, int64_t id) +{ + std::unique_ptr d(response); + RpcMessage message; + message.set_type(RESPONSE); + message.set_id(id); + message.set_response(response->SerializeAsString()); // FIXME: error check + codec_.send(conn_, message); +} + diff --git a/include/Third_Lib/muduo/net/protorpc/RpcChannel.h b/include/Third_Lib/muduo/net/protorpc/RpcChannel.h new file mode 100644 index 0000000..172b41e --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcChannel.h @@ -0,0 +1,152 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCCHANNEL_H +#define MUDUO_NET_PROTORPC_RPCCHANNEL_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Mutex.h" +#include "muduo/net/protorpc/RpcCodec.h" + +#include + +#include + +// Service and RpcChannel classes are incorporated from +// google/protobuf/service.h + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +namespace google { +namespace protobuf { + +// Defined in other files. +class Descriptor; // descriptor.h +class ServiceDescriptor; // descriptor.h +class MethodDescriptor; // descriptor.h +class Message; // message.h + +class Closure; + +class RpcController; +class Service; + +} // namespace protobuf +} // namespace google + + +namespace muduo +{ +namespace net +{ + +// Abstract interface for an RPC channel. An RpcChannel represents a +// communication line to a Service which can be used to call that Service's +// methods. The Service may be running on another machine. Normally, you +// should not call an RpcChannel directly, but instead construct a stub Service +// wrapping it. Example: +// FIXME: update here +// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234"); +// MyService* service = new MyService::Stub(channel); +// service->MyMethod(request, &response, callback); +class RpcChannel : public ::google::protobuf::RpcChannel +{ + public: + RpcChannel(); + + explicit RpcChannel(const TcpConnectionPtr& conn); + + ~RpcChannel() override; + + void setConnection(const TcpConnectionPtr& conn) + { + conn_ = conn; + } + + void setServices(const std::map* services) + { + services_ = services; + } + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). + void CallMethod(const ::google::protobuf::MethodDescriptor* method, + ::google::protobuf::RpcController* controller, + const ::google::protobuf::Message* request, + ::google::protobuf::Message* response, + ::google::protobuf::Closure* done) override; + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + + private: + void onRpcMessage(const TcpConnectionPtr& conn, + const RpcMessagePtr& messagePtr, + Timestamp receiveTime); + + void doneCallback(::google::protobuf::Message* response, int64_t id); + + struct OutstandingCall + { + ::google::protobuf::Message* response; + ::google::protobuf::Closure* done; + }; + + RpcCodec codec_; + TcpConnectionPtr conn_; + AtomicInt64 id_; + + MutexLock mutex_; + std::map outstandings_ GUARDED_BY(mutex_); + + const std::map* services_; +}; +typedef std::shared_ptr RpcChannelPtr; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCCHANNEL_H diff --git a/include/Third_Lib/muduo/net/protorpc/RpcCodec.cc b/include/Third_Lib/muduo/net/protorpc/RpcCodec.cc new file mode 100644 index 0000000..e466e1d --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcCodec.cc @@ -0,0 +1,37 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcCodec.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/TcpConnection.h" + +#include "muduo/net/protorpc/rpc.pb.h" +#include "muduo/net/protorpc/google-inl.h" + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + int ProtobufVersionCheck() + { + GOOGLE_PROTOBUF_VERIFY_VERSION; + return 0; + } + int dummy __attribute__ ((unused)) = ProtobufVersionCheck(); +} + +namespace muduo +{ +namespace net +{ +const char rpctag [] = "RPC0"; +} +} diff --git a/include/Third_Lib/muduo/net/protorpc/RpcCodec.h b/include/Third_Lib/muduo/net/protorpc/RpcCodec.h new file mode 100644 index 0000000..07fab9c --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcCodec.h @@ -0,0 +1,45 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCCODEC_H +#define MUDUO_NET_PROTORPC_RPCCODEC_H + +#include "muduo/base/Timestamp.h" +#include "muduo/net/protobuf/ProtobufCodecLite.h" + +namespace muduo +{ +namespace net +{ + +class Buffer; +class TcpConnection; +typedef std::shared_ptr TcpConnectionPtr; + +class RpcMessage; +typedef std::shared_ptr RpcMessagePtr; +extern const char rpctag[];// = "RPC0"; + +// wire format +// +// Field Length Content +// +// size 4-byte N+8 +// "RPC0" 4-byte +// payload N-byte +// checksum 4-byte adler32 of "RPC0"+payload +// + +typedef ProtobufCodecLiteT RpcCodec; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCCODEC_H diff --git a/include/Third_Lib/muduo/net/protorpc/RpcCodec_test.cc b/include/Third_Lib/muduo/net/protorpc/RpcCodec_test.cc new file mode 100644 index 0000000..645fffd --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcCodec_test.cc @@ -0,0 +1,81 @@ +#undef NDEBUG +#include "muduo/net/protorpc/RpcCodec.h" +#include "muduo/net/protorpc/rpc.pb.h" +#include "muduo/net/protobuf/ProtobufCodecLite.h" +#include "muduo/net/Buffer.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void rpcMessageCallback(const TcpConnectionPtr&, + const RpcMessagePtr&, + Timestamp) +{ +} + +MessagePtr g_msgptr; +void messageCallback(const TcpConnectionPtr&, + const MessagePtr& msg, + Timestamp) +{ + g_msgptr = msg; +} + +void print(const Buffer& buf) +{ + printf("encoded to %zd bytes\n", buf.readableBytes()); + for (size_t i = 0; i < buf.readableBytes(); ++i) + { + unsigned char ch = static_cast(buf.peek()[i]); + + printf("%2zd: 0x%02x %c\n", i, ch, isgraph(ch) ? ch : ' '); + } +} + +char rpctag[] = "RPC0"; + +int main() +{ + RpcMessage message; + message.set_type(REQUEST); + message.set_id(2); + char wire[] = "\0\0\0\x13" "RPC0" "\x08\x01\x11\x02\0\0\0\0\0\0\0" "\x0f\xef\x01\x32"; + string expected(wire, sizeof(wire)-1); + string s1, s2; + Buffer buf1, buf2; + { + RpcCodec codec(rpcMessageCallback); + codec.fillEmptyBuffer(&buf1, message); + print(buf1); + s1 = buf1.toStringPiece().as_string(); + } + + { + ProtobufCodecLite codec(&RpcMessage::default_instance(), "RPC0", messageCallback); + codec.fillEmptyBuffer(&buf2, message); + print(buf2); + s2 = buf2.toStringPiece().as_string(); + codec.onMessage(TcpConnectionPtr(), &buf1, Timestamp::now()); + assert(g_msgptr); + assert(g_msgptr->DebugString() == message.DebugString()); + g_msgptr.reset(); + } + assert(s1 == s2); + assert(s1 == expected); + assert(s2 == expected); + + { + Buffer buf; + ProtobufCodecLite codec(&RpcMessage::default_instance(), "XYZ", messageCallback); + codec.fillEmptyBuffer(&buf, message); + print(buf); + s2 = buf.toStringPiece().as_string(); + codec.onMessage(TcpConnectionPtr(), &buf, Timestamp::now()); + assert(g_msgptr); + assert(g_msgptr->DebugString() == message.DebugString()); + } + + google::protobuf::ShutdownProtobufLibrary(); +} diff --git a/include/Third_Lib/muduo/net/protorpc/RpcServer.cc b/include/Third_Lib/muduo/net/protorpc/RpcServer.cc new file mode 100644 index 0000000..fc1248b --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcServer.cc @@ -0,0 +1,68 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/protorpc/RpcChannel.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +RpcServer::RpcServer(EventLoop* loop, + const InetAddress& listenAddr) + : server_(loop, listenAddr, "RpcServer") +{ + server_.setConnectionCallback( + std::bind(&RpcServer::onConnection, this, _1)); +// server_.setMessageCallback( +// std::bind(&RpcServer::onMessage, this, _1, _2, _3)); +} + +void RpcServer::registerService(google::protobuf::Service* service) +{ + const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); + services_[desc->full_name()] = service; +} + +void RpcServer::start() +{ + server_.start(); +} + +void RpcServer::onConnection(const TcpConnectionPtr& conn) +{ + LOG_INFO << "RpcServer - " << conn->peerAddress().toIpPort() << " -> " + << conn->localAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + if (conn->connected()) + { + RpcChannelPtr channel(new RpcChannel(conn)); + channel->setServices(&services_); + conn->setMessageCallback( + std::bind(&RpcChannel::onMessage, get_pointer(channel), _1, _2, _3)); + conn->setContext(channel); + } + else + { + conn->setContext(RpcChannelPtr()); + // FIXME: + } +} + +// void RpcServer::onMessage(const TcpConnectionPtr& conn, +// Buffer* buf, +// Timestamp time) +// { +// RpcChannelPtr& channel = boost::any_cast(conn->getContext()); +// channel->onMessage(conn, buf, time); +// } + diff --git a/include/Third_Lib/muduo/net/protorpc/RpcServer.h b/include/Third_Lib/muduo/net/protorpc/RpcServer.h new file mode 100644 index 0000000..6818801 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcServer.h @@ -0,0 +1,57 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCSERVER_H +#define MUDUO_NET_PROTORPC_RPCSERVER_H + +#include "muduo/net/TcpServer.h" + +namespace google { +namespace protobuf { + +class Service; + +} // namespace protobuf +} // namespace google + +namespace muduo +{ +namespace net +{ + +class RpcServer +{ + public: + RpcServer(EventLoop* loop, + const InetAddress& listenAddr); + + void setThreadNum(int numThreads) + { + server_.setThreadNum(numThreads); + } + + void registerService(::google::protobuf::Service*); + void start(); + + private: + void onConnection(const TcpConnectionPtr& conn); + + // void onMessage(const TcpConnectionPtr& conn, + // Buffer* buf, + // Timestamp time); + + TcpServer server_; + std::map services_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCSERVER_H diff --git a/include/Third_Lib/muduo/net/protorpc/google-inl.h b/include/Third_Lib/muduo/net/protorpc/google-inl.h new file mode 100644 index 0000000..2a905a9 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/google-inl.h @@ -0,0 +1,84 @@ +// ByteSizeConsistencyError and InitializationErrorMessage are +// copied from google/protobuf/message_lite.cc + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Authors: wink@google.com (Wink Saville), +// kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +// When serializing, we first compute the byte size, then serialize the message. +// If serialization produces a different number of bytes than expected, we +// call this function, which crashes. The problem could be due to a bug in the +// protobuf implementation but is more likely caused by concurrent modification +// of the message. This function attempts to distinguish between the two and +// provide a useful error message. +inline +void ByteSizeConsistencyError(int byte_size_before_serialization, + int byte_size_after_serialization, + int bytes_produced_by_serialization) +{ + GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) + << "Protocol message was modified concurrently during serialization."; + GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) + << "Byte size calculation and serialization were inconsistent. This " + "may indicate a bug in protocol buffers or it may be caused by " + "concurrent modification of the message."; + GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; +} + +inline +std::string InitializationErrorMessage(const char* action, + const google::protobuf::MessageLite& message) +{ + // Note: We want to avoid depending on strutil in the lite library, otherwise + // we'd use: + // + // return strings::Substitute( + // "Can't $0 message of type \"$1\" because it is missing required " + // "fields: $2", + // action, message.GetTypeName(), + // message.InitializationErrorString()); + + std::string result; + result += "Can't "; + result += action; + result += " message of type \""; + result += message.GetTypeName(); + result += "\" because it is missing required fields: "; + result += message.InitializationErrorString(); + return result; +} + + diff --git a/include/Third_Lib/muduo/net/protorpc/rpc.proto b/include/Third_Lib/muduo/net/protorpc/rpc.proto new file mode 100644 index 0000000..941e235 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/rpc.proto @@ -0,0 +1,36 @@ +package muduo.net; +// option go_package = "muduorpc"; +option java_package = "com.chenshuo.muduo.protorpc"; +option java_outer_classname = "RpcProto"; + +enum MessageType +{ + REQUEST = 1; + RESPONSE = 2; + ERROR = 3; // not used +} + +enum ErrorCode +{ + NO_ERROR = 0; + WRONG_PROTO = 1; + NO_SERVICE = 2; + NO_METHOD = 3; + INVALID_REQUEST = 4; + INVALID_RESPONSE = 5; + TIMEOUT = 6; +} + +message RpcMessage +{ + required MessageType type = 1; + required fixed64 id = 2; + + optional string service = 3; + optional string method = 4; + optional bytes request = 5; + + optional bytes response = 6; + + optional ErrorCode error = 7; +} diff --git a/include/Third_Lib/muduo/net/protorpc/rpcservice.proto b/include/Third_Lib/muduo/net/protorpc/rpcservice.proto new file mode 100644 index 0000000..f973234 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/rpcservice.proto @@ -0,0 +1,44 @@ +package muduo.net; + +option cc_generic_services = true; +option java_generic_services = true; +option py_generic_services = true; + +option java_package = "com.chenshuo.muduo.protorpc"; +option java_outer_classname = "RpcServiceProto"; + +//import "google/protobuf/descriptor.proto"; +import "rpc.proto"; + +message ListRpcRequest +{ + optional string service_name = 1; + optional bool list_method = 2; +} + +message ListRpcResponse +{ + required ErrorCode error = 1; + repeated string service_name = 2; + repeated string method_name = 3; +} + +message GetServiceRequest +{ + required string service_name = 1; +} + +message GetServiceResponse +{ + required ErrorCode error = 1; + repeated string proto_file = 2; + repeated string proto_file_name = 3; +} + +// the meta service +service RpcService +{ + rpc listRpc (ListRpcRequest) returns (ListRpcResponse); + rpc getService (GetServiceRequest) returns (GetServiceResponse); +} + diff --git a/include/Third_Lib/muduo/net/tests/Buffer_unittest.cc b/include/Third_Lib/muduo/net/tests/Buffer_unittest.cc new file mode 100644 index 0000000..af7fb81 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/Buffer_unittest.cc @@ -0,0 +1,170 @@ +#include "muduo/net/Buffer.h" + +//#define BOOST_TEST_MODULE BufferTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::net::Buffer; + +BOOST_AUTO_TEST_CASE(testBufferAppendRetrieve) +{ + Buffer buf; + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + const string str(200, 'x'); + buf.append(str); + BOOST_CHECK_EQUAL(buf.readableBytes(), str.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + const string str2 = buf.retrieveAsString(50); + BOOST_CHECK_EQUAL(str2.size(), 50); + BOOST_CHECK_EQUAL(buf.readableBytes(), str.size() - str2.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); + BOOST_CHECK_EQUAL(str2, string(50, 'x')); + + buf.append(str); + BOOST_CHECK_EQUAL(buf.readableBytes(), 2*str.size() - str2.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - 2*str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); + + const string str3 = buf.retrieveAllAsString(); + BOOST_CHECK_EQUAL(str3.size(), 350); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + BOOST_CHECK_EQUAL(str3, string(350, 'x')); +} + +BOOST_AUTO_TEST_CASE(testBufferGrow) +{ + Buffer buf; + buf.append(string(400, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 400); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); + + buf.retrieve(50); + BOOST_CHECK_EQUAL(buf.readableBytes(), 350); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); + + buf.append(string(1000, 'z')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 1350); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); // FIXME + + buf.retrieveAll(); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), 1400); // FIXME + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferInsideGrow) +{ + Buffer buf; + buf.append(string(800, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 800); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); + + buf.retrieve(500); + BOOST_CHECK_EQUAL(buf.readableBytes(), 300); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+500); + + buf.append(string(300, 'z')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 600); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-600); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferShrink) +{ + Buffer buf; + buf.append(string(2000, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 2000); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + buf.retrieve(1500); + BOOST_CHECK_EQUAL(buf.readableBytes(), 500); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+1500); + + buf.shrink(0); + BOOST_CHECK_EQUAL(buf.readableBytes(), 500); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-500); + BOOST_CHECK_EQUAL(buf.retrieveAllAsString(), string(500, 'y')); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferPrepend) +{ + Buffer buf; + buf.append(string(200, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 200); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + int x = 0; + buf.prepend(&x, sizeof x); + BOOST_CHECK_EQUAL(buf.readableBytes(), 204); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend - 4); +} + +BOOST_AUTO_TEST_CASE(testBufferReadInt) +{ + Buffer buf; + buf.append("HTTP"); + + BOOST_CHECK_EQUAL(buf.readableBytes(), 4); + BOOST_CHECK_EQUAL(buf.peekInt8(), 'H'); + int top16 = buf.peekInt16(); + BOOST_CHECK_EQUAL(top16, 'H'*256 + 'T'); + BOOST_CHECK_EQUAL(buf.peekInt32(), top16*65536 + 'T'*256 + 'P'); + + BOOST_CHECK_EQUAL(buf.readInt8(), 'H'); + BOOST_CHECK_EQUAL(buf.readInt16(), 'T'*256 + 'T'); + BOOST_CHECK_EQUAL(buf.readInt8(), 'P'); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + + buf.appendInt8(-1); + buf.appendInt16(-2); + buf.appendInt32(-3); + BOOST_CHECK_EQUAL(buf.readableBytes(), 7); + BOOST_CHECK_EQUAL(buf.readInt8(), -1); + BOOST_CHECK_EQUAL(buf.readInt16(), -2); + BOOST_CHECK_EQUAL(buf.readInt32(), -3); +} + +BOOST_AUTO_TEST_CASE(testBufferFindEOL) +{ + Buffer buf; + buf.append(string(100000, 'x')); + const char* null = NULL; + BOOST_CHECK_EQUAL(buf.findEOL(), null); + BOOST_CHECK_EQUAL(buf.findEOL(buf.peek()+90000), null); +} + +void output(Buffer&& buf, const void* inner) +{ + Buffer newbuf(std::move(buf)); + // printf("New Buffer at %p, inner %p\n", &newbuf, newbuf.peek()); + BOOST_CHECK_EQUAL(inner, newbuf.peek()); +} + +// NOTE: This test fails in g++ 4.4, passes in g++ 4.6. +BOOST_AUTO_TEST_CASE(testMove) +{ + Buffer buf; + buf.append("muduo", 5); + const void* inner = buf.peek(); + // printf("Buffer at %p, inner %p\n", &buf, inner); + output(std::move(buf), inner); +} diff --git a/include/Third_Lib/muduo/net/tests/CMakeLists.txt b/include/Third_Lib/muduo/net/tests/CMakeLists.txt new file mode 100644 index 0000000..a7aa3a0 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/CMakeLists.txt @@ -0,0 +1,48 @@ +add_executable(channel_test Channel_test.cc) +target_link_libraries(channel_test muduo_net) + +add_executable(echoserver_unittest EchoServer_unittest.cc) +target_link_libraries(echoserver_unittest muduo_net) + +add_executable(echoclient_unittest EchoClient_unittest.cc) +target_link_libraries(echoclient_unittest muduo_net) + +add_executable(eventloop_unittest EventLoop_unittest.cc) +target_link_libraries(eventloop_unittest muduo_net) + +add_executable(eventloopthread_unittest EventLoopThread_unittest.cc) +target_link_libraries(eventloopthread_unittest muduo_net) + +add_executable(eventloopthreadpool_unittest EventLoopThreadPool_unittest.cc) +target_link_libraries(eventloopthreadpool_unittest muduo_net) + +if(BOOSTTEST_LIBRARY) +add_executable(buffer_unittest Buffer_unittest.cc) +target_link_libraries(buffer_unittest muduo_net boost_unit_test_framework) +add_test(NAME buffer_unittest COMMAND buffer_unittest) + +add_executable(inetaddress_unittest InetAddress_unittest.cc) +target_link_libraries(inetaddress_unittest muduo_net boost_unit_test_framework) +add_test(NAME inetaddress_unittest COMMAND inetaddress_unittest) + +if(ZLIB_FOUND) + add_executable(zlibstream_unittest ZlibStream_unittest.cc) + target_link_libraries(zlibstream_unittest muduo_net boost_unit_test_framework z) + # set_target_properties(zlibstream_unittest PROPERTIES COMPILE_FLAGS "-std=c++0x") +endif() + +endif() + +add_executable(tcpclient_reg1 TcpClient_reg1.cc) +target_link_libraries(tcpclient_reg1 muduo_net) + +add_executable(tcpclient_reg2 TcpClient_reg2.cc) +target_link_libraries(tcpclient_reg2 muduo_net) + +add_executable(tcpclient_reg3 TcpClient_reg3.cc) +target_link_libraries(tcpclient_reg3 muduo_net) + +add_executable(timerqueue_unittest TimerQueue_unittest.cc) +target_link_libraries(timerqueue_unittest muduo_net) +add_test(NAME timerqueue_unittest COMMAND timerqueue_unittest) + diff --git a/include/Third_Lib/muduo/net/tests/Channel_test.cc b/include/Third_Lib/muduo/net/tests/Channel_test.cc new file mode 100644 index 0000000..6276531 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/Channel_test.cc @@ -0,0 +1,112 @@ +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" + +#include +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(const char* msg) +{ + static std::map lasts; + Timestamp& last = lasts[msg]; + Timestamp now = Timestamp::now(); + printf("%s tid %d %s delay %f\n", now.toString().c_str(), CurrentThread::tid(), + msg, timeDifference(now, last)); + last = now; +} + +namespace muduo +{ +namespace net +{ +namespace detail +{ +int createTimerfd(); +void readTimerfd(int timerfd, Timestamp now); +} +} +} + +// Use relative time, immunized to wall clock changes. +class PeriodicTimer +{ + public: + PeriodicTimer(EventLoop* loop, double interval, const TimerCallback& cb) + : loop_(loop), + timerfd_(muduo::net::detail::createTimerfd()), + timerfdChannel_(loop, timerfd_), + interval_(interval), + cb_(cb) + { + timerfdChannel_.setReadCallback( + std::bind(&PeriodicTimer::handleRead, this)); + timerfdChannel_.enableReading(); + } + + void start() + { + struct itimerspec spec; + memZero(&spec, sizeof spec); + spec.it_interval = toTimeSpec(interval_); + spec.it_value = spec.it_interval; + int ret = ::timerfd_settime(timerfd_, 0 /* relative timer */, &spec, NULL); + if (ret) + { + LOG_SYSERR << "timerfd_settime()"; + } + } + + ~PeriodicTimer() + { + timerfdChannel_.disableAll(); + timerfdChannel_.remove(); + ::close(timerfd_); + } + + private: + void handleRead() + { + loop_->assertInLoopThread(); + muduo::net::detail::readTimerfd(timerfd_, Timestamp::now()); + if (cb_) + cb_(); + } + + static struct timespec toTimeSpec(double seconds) + { + struct timespec ts; + memZero(&ts, sizeof ts); + const int64_t kNanoSecondsPerSecond = 1000000000; + const int kMinInterval = 100000; + int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); + if (nanoseconds < kMinInterval) + nanoseconds = kMinInterval; + ts.tv_sec = static_cast(nanoseconds / kNanoSecondsPerSecond); + ts.tv_nsec = static_cast(nanoseconds % kNanoSecondsPerSecond); + return ts; + } + + EventLoop* loop_; + const int timerfd_; + Channel timerfdChannel_; + const double interval_; // in seconds + TimerCallback cb_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid() + << " Try adjusting the wall clock, see what happens."; + EventLoop loop; + PeriodicTimer timer(&loop, 1, std::bind(print, "PeriodicTimer")); + timer.start(); + loop.runEvery(1, std::bind(print, "EventLoop::runEvery")); + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/EchoClient_unittest.cc b/include/Third_Lib/muduo/net/tests/EchoClient_unittest.cc new file mode 100644 index 0000000..44d973a --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EchoClient_unittest.cc @@ -0,0 +1,114 @@ +#include "muduo/net/TcpClient.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; +class EchoClient; +std::vector> clients; +int current = 0; + +class EchoClient : noncopyable +{ + public: + EchoClient(EventLoop* loop, const InetAddress& listenAddr, const string& id) + : loop_(loop), + client_(loop, listenAddr, "EchoClient"+id) + { + client_.setConnectionCallback( + std::bind(&EchoClient::onConnection, this, _1)); + client_.setMessageCallback( + std::bind(&EchoClient::onMessage, this, _1, _2, _3)); + //client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + // void stop(); + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->localAddress().toIpPort() << " -> " + << conn->peerAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + if (conn->connected()) + { + ++current; + if (implicit_cast(current) < clients.size()) + { + clients[current]->connect(); + } + LOG_INFO << "*** connected " << current; + } + conn->send("world\n"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + string msg(buf->retrieveAllAsString()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); + if (msg == "quit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + else if (msg == "shutdown\n") + { + loop_->quit(); + } + else + { + conn->send(msg); + } + } + + EventLoop* loop_; + TcpClient client_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 1) + { + EventLoop loop; + bool ipv6 = argc > 3; + InetAddress serverAddr(argv[1], 2000, ipv6); + + int n = 1; + if (argc > 2) + { + n = atoi(argv[2]); + } + + clients.reserve(n); + for (int i = 0; i < n; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "%d", i+1); + clients.emplace_back(new EchoClient(&loop, serverAddr, buf)); + } + + clients[current]->connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip [current#]\n", argv[0]); + } +} + diff --git a/include/Third_Lib/muduo/net/tests/EchoServer_unittest.cc b/include/Third_Lib/muduo/net/tests/EchoServer_unittest.cc new file mode 100644 index 0000000..0875668 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EchoServer_unittest.cc @@ -0,0 +1,86 @@ +#include "muduo/net/TcpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; + +class EchoServer +{ + public: + EchoServer(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "EchoServer") + { + server_.setConnectionCallback( + std::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + std::bind(&EchoServer::onMessage, this, _1, _2, _3)); + server_.setThreadNum(numThreads); + } + + void start() + { + server_.start(); + } + // void stop(); + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->peerAddress().toIpPort() << " -> " + << conn->localAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + LOG_INFO << conn->getTcpInfoString(); + + conn->send("hello\n"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + string msg(buf->retrieveAllAsString()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); + if (msg == "exit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + if (msg == "quit\n") + { + loop_->quit(); + } + conn->send(msg); + } + + EventLoop* loop_; + TcpServer server_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); + if (argc > 1) + { + numThreads = atoi(argv[1]); + } + bool ipv6 = argc > 2; + EventLoop loop; + InetAddress listenAddr(2000, false, ipv6); + EchoServer server(&loop, listenAddr); + + server.start(); + + loop.loop(); +} + diff --git a/include/Third_Lib/muduo/net/tests/EventLoopThreadPool_unittest.cc b/include/Third_Lib/muduo/net/tests/EventLoopThreadPool_unittest.cc new file mode 100644 index 0000000..1bf1bd3 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EventLoopThreadPool_unittest.cc @@ -0,0 +1,68 @@ +#include "muduo/net/EventLoopThreadPool.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(EventLoop* p = NULL) +{ + printf("main(): pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +void init(EventLoop* p) +{ + printf("init(): pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +int main() +{ + print(); + + EventLoop loop; + loop.runAfter(11, std::bind(&EventLoop::quit, &loop)); + + { + printf("Single thread %p:\n", &loop); + EventLoopThreadPool model(&loop, "single"); + model.setThreadNum(0); + model.start(init); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + } + + { + printf("Another thread:\n"); + EventLoopThreadPool model(&loop, "another"); + model.setThreadNum(1); + model.start(init); + EventLoop* nextLoop = model.getNextLoop(); + nextLoop->runAfter(2, std::bind(print, nextLoop)); + assert(nextLoop != &loop); + assert(nextLoop == model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + ::sleep(3); + } + + { + printf("Three threads:\n"); + EventLoopThreadPool model(&loop, "three"); + model.setThreadNum(3); + model.start(init); + EventLoop* nextLoop = model.getNextLoop(); + nextLoop->runInLoop(std::bind(print, nextLoop)); + assert(nextLoop != &loop); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + } + + loop.loop(); +} + diff --git a/include/Third_Lib/muduo/net/tests/EventLoopThread_unittest.cc b/include/Third_Lib/muduo/net/tests/EventLoopThread_unittest.cc new file mode 100644 index 0000000..d67c128 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EventLoopThread_unittest.cc @@ -0,0 +1,48 @@ +#include "muduo/net/EventLoopThread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" +#include "muduo/base/CountDownLatch.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(EventLoop* p = NULL) +{ + printf("print: pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +void quit(EventLoop* p) +{ + print(p); + p->quit(); +} + +int main() +{ + print(); + + { + EventLoopThread thr1; // never start + } + + { + // dtor calls quit() + EventLoopThread thr2; + EventLoop* loop = thr2.startLoop(); + loop->runInLoop(std::bind(print, loop)); + CurrentThread::sleepUsec(500 * 1000); + } + + { + // quit() before dtor + EventLoopThread thr3; + EventLoop* loop = thr3.startLoop(); + loop->runInLoop(std::bind(quit, loop)); + CurrentThread::sleepUsec(500 * 1000); + } +} + diff --git a/include/Third_Lib/muduo/net/tests/EventLoop_unittest.cc b/include/Third_Lib/muduo/net/tests/EventLoop_unittest.cc new file mode 100644 index 0000000..6cb6d7d --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EventLoop_unittest.cc @@ -0,0 +1,42 @@ +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +EventLoop* g_loop; + +void callback() +{ + printf("callback(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + EventLoop anotherLoop; +} + +void threadFunc() +{ + printf("threadFunc(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + + assert(EventLoop::getEventLoopOfCurrentThread() == NULL); + EventLoop loop; + assert(EventLoop::getEventLoopOfCurrentThread() == &loop); + loop.runAfter(1.0, callback); + loop.loop(); +} + +int main() +{ + printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + + assert(EventLoop::getEventLoopOfCurrentThread() == NULL); + EventLoop loop; + assert(EventLoop::getEventLoopOfCurrentThread() == &loop); + + Thread thread(threadFunc); + thread.start(); + + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/InetAddress_unittest.cc b/include/Third_Lib/muduo/net/tests/InetAddress_unittest.cc new file mode 100644 index 0000000..bdd31e0 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/InetAddress_unittest.cc @@ -0,0 +1,70 @@ +#include "muduo/net/InetAddress.h" + +#include "muduo/base/Logging.h" + +//#define BOOST_TEST_MODULE InetAddressTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::net::InetAddress; + +BOOST_AUTO_TEST_CASE(testInetAddress) +{ + InetAddress addr0(1234); + BOOST_CHECK_EQUAL(addr0.toIp(), string("0.0.0.0")); + BOOST_CHECK_EQUAL(addr0.toIpPort(), string("0.0.0.0:1234")); + BOOST_CHECK_EQUAL(addr0.port(), 1234); + + InetAddress addr1(4321, true); + BOOST_CHECK_EQUAL(addr1.toIp(), string("127.0.0.1")); + BOOST_CHECK_EQUAL(addr1.toIpPort(), string("127.0.0.1:4321")); + BOOST_CHECK_EQUAL(addr1.port(), 4321); + + InetAddress addr2("1.2.3.4", 8888); + BOOST_CHECK_EQUAL(addr2.toIp(), string("1.2.3.4")); + BOOST_CHECK_EQUAL(addr2.toIpPort(), string("1.2.3.4:8888")); + BOOST_CHECK_EQUAL(addr2.port(), 8888); + + InetAddress addr3("255.254.253.252", 65535); + BOOST_CHECK_EQUAL(addr3.toIp(), string("255.254.253.252")); + BOOST_CHECK_EQUAL(addr3.toIpPort(), string("255.254.253.252:65535")); + BOOST_CHECK_EQUAL(addr3.port(), 65535); +} + +BOOST_AUTO_TEST_CASE(testInet6Address) +{ + InetAddress addr0(1234, false, true); + BOOST_CHECK_EQUAL(addr0.toIp(), string("::")); + BOOST_CHECK_EQUAL(addr0.toIpPort(), string("[::]:1234")); + BOOST_CHECK_EQUAL(addr0.port(), 1234); + + InetAddress addr1(1234, true, true); + BOOST_CHECK_EQUAL(addr1.toIp(), string("::1")); + BOOST_CHECK_EQUAL(addr1.toIpPort(), string("[::1]:1234")); + BOOST_CHECK_EQUAL(addr1.port(), 1234); + + InetAddress addr2("2001:db8::1", 8888, true); + BOOST_CHECK_EQUAL(addr2.toIp(), string("2001:db8::1")); + BOOST_CHECK_EQUAL(addr2.toIpPort(), string("[2001:db8::1]:8888")); + BOOST_CHECK_EQUAL(addr2.port(), 8888); + + InetAddress addr3("fe80::1234:abcd:1", 8888); + BOOST_CHECK_EQUAL(addr3.toIp(), string("fe80::1234:abcd:1")); + BOOST_CHECK_EQUAL(addr3.toIpPort(), string("[fe80::1234:abcd:1]:8888")); + BOOST_CHECK_EQUAL(addr3.port(), 8888); +} + +BOOST_AUTO_TEST_CASE(testInetAddressResolve) +{ + InetAddress addr(80); + if (InetAddress::resolve("google.com", &addr)) + { + LOG_INFO << "google.com resolved to " << addr.toIpPort(); + } + else + { + LOG_ERROR << "Unable to resolve google.com"; + } +} diff --git a/include/Third_Lib/muduo/net/tests/TcpClient_reg1.cc b/include/Third_Lib/muduo/net/tests/TcpClient_reg1.cc new file mode 100644 index 0000000..41b76b2 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TcpClient_reg1.cc @@ -0,0 +1,29 @@ +// TcpClient::stop() called in the same iteration of IO event + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +TcpClient* g_client; + +void timeout() +{ + LOG_INFO << "timeout"; + g_client->stop(); +} + +int main(int argc, char* argv[]) +{ + EventLoop loop; + InetAddress serverAddr("127.0.0.1", 2); // no such server + TcpClient client(&loop, serverAddr, "TcpClient"); + g_client = &client; + loop.runAfter(0.0, timeout); + loop.runAfter(1.0, std::bind(&EventLoop::quit, &loop)); + client.connect(); + CurrentThread::sleepUsec(100 * 1000); + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/TcpClient_reg2.cc b/include/Third_Lib/muduo/net/tests/TcpClient_reg2.cc new file mode 100644 index 0000000..1637dbd --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TcpClient_reg2.cc @@ -0,0 +1,30 @@ +// TcpClient destructs when TcpConnection is connected but unique. + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +void threadFunc(EventLoop* loop) +{ + InetAddress serverAddr("127.0.0.1", 1234); // should succeed + TcpClient client(loop, serverAddr, "TcpClient"); + client.connect(); + + CurrentThread::sleepUsec(1000*1000); + // client destructs when connected. +} + +int main(int argc, char* argv[]) +{ + Logger::setLogLevel(Logger::DEBUG); + + EventLoop loop; + loop.runAfter(3.0, std::bind(&EventLoop::quit, &loop)); + Thread thr(std::bind(threadFunc, &loop)); + thr.start(); + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/TcpClient_reg3.cc b/include/Third_Lib/muduo/net/tests/TcpClient_reg3.cc new file mode 100644 index 0000000..bb1e5ee --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TcpClient_reg3.cc @@ -0,0 +1,24 @@ +// TcpClient destructs in a different thread. + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoopThread.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +int main(int argc, char* argv[]) +{ + Logger::setLogLevel(Logger::DEBUG); + + EventLoopThread loopThread; + { + InetAddress serverAddr("127.0.0.1", 1234); // should succeed + TcpClient client(loopThread.startLoop(), serverAddr, "TcpClient"); + client.connect(); + CurrentThread::sleepUsec(500 * 1000); // wait for connect + client.disconnect(); + } + + CurrentThread::sleepUsec(1000 * 1000); +} diff --git a/include/Third_Lib/muduo/net/tests/TimerQueue_unittest.cc b/include/Third_Lib/muduo/net/tests/TimerQueue_unittest.cc new file mode 100644 index 0000000..65cff93 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TimerQueue_unittest.cc @@ -0,0 +1,66 @@ +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" +#include "muduo/base/Thread.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int cnt = 0; +EventLoop* g_loop; + +void printTid() +{ + printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + printf("now %s\n", Timestamp::now().toString().c_str()); +} + +void print(const char* msg) +{ + printf("msg %s %s\n", Timestamp::now().toString().c_str(), msg); + if (++cnt == 20) + { + g_loop->quit(); + } +} + +void cancel(TimerId timer) +{ + g_loop->cancel(timer); + printf("cancelled at %s\n", Timestamp::now().toString().c_str()); +} + +int main() +{ + printTid(); + sleep(1); + { + EventLoop loop; + g_loop = &loop; + + print("main"); + loop.runAfter(1, std::bind(print, "once1")); + loop.runAfter(1.5, std::bind(print, "once1.5")); + loop.runAfter(2.5, std::bind(print, "once2.5")); + loop.runAfter(3.5, std::bind(print, "once3.5")); + TimerId t45 = loop.runAfter(4.5, std::bind(print, "once4.5")); + loop.runAfter(4.2, std::bind(cancel, t45)); + loop.runAfter(4.8, std::bind(cancel, t45)); + loop.runEvery(2, std::bind(print, "every2")); + TimerId t3 = loop.runEvery(3, std::bind(print, "every3")); + loop.runAfter(9.001, std::bind(cancel, t3)); + + loop.loop(); + print("main loop exits"); + } + sleep(1); + { + EventLoopThread loopThread; + EventLoop* loop = loopThread.startLoop(); + loop->runAfter(2, printTid); + sleep(3); + print("thread loop exits"); + } +} diff --git a/include/Third_Lib/muduo/net/tests/ZlibStream_unittest.cc b/include/Third_Lib/muduo/net/tests/ZlibStream_unittest.cc new file mode 100644 index 0000000..144dda0 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/ZlibStream_unittest.cc @@ -0,0 +1,91 @@ +#include "muduo/net/ZlibStream.h" + +#include "muduo/base/Logging.h" + +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +#include + +BOOST_AUTO_TEST_CASE(testZlibOutputStream) +{ + muduo::net::Buffer output; + { + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(output.readableBytes(), 0); + } + BOOST_CHECK_EQUAL(output.readableBytes(), 8); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream1) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + stream.finish(); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream2) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); + stream.finish(); + // printf("%zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream3) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + for (int i = 0; i < 1024*1024; ++i) + { + BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); + } + stream.finish(); + // printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream4) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + muduo::string input; + for (int i = 0; i < 32768; ++i) + { + input += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-"[rand() % 64]; + } + + for (int i = 0; i < 10; ++i) + { + BOOST_CHECK(stream.write(input)); + } + stream.finish(); + // printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream5) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + muduo::string input(1024*1024, '_'); + for (int i = 0; i < 64; ++i) + { + BOOST_CHECK(stream.write(input)); + } + printf("bufsiz %d\n", stream.internalOutputBufferSize()); + LOG_INFO << "total_in " << stream.inputBytes(); + LOG_INFO << "total_out " << stream.outputBytes(); + stream.finish(); + printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} diff --git a/include/Type.hpp b/include/Type.hpp deleted file mode 100644 index 65ed292..0000000 --- a/include/Type.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SRC_TYPE_H -#define SRC_TYPE_H - -#pragma once - -#include "boost/lockfree/queue.hpp" -template -using lfqueue = boost::lockfree::queue; - - - -#endif //SRC_TYPE_H \ No newline at end of file diff --git a/include/Udp.hpp b/include/Udp.hpp index 978aae0..7956704 100644 --- a/include/Udp.hpp +++ b/include/Udp.hpp @@ -3,30 +3,42 @@ #pragma once +#include +#include +#include +#include +#include +#include +#include +#include + //暂时以int表示ip, 有需要则封装成类 using IP = int; namespace port { - const constexpr int kCLI_LOGIN_ = 20800; - const constexpr int kCLI_BEAT_ = 20801; - const constexpr int kMIR_BEAT_ = 20802; - const constexpr int kINS_MSG_ = 20803; + const constexpr size_t kCLI_LOGIN_ = 20800; + const constexpr size_t kCLI_BEAT_ = 20801; + const constexpr size_t kMIR_BEAT_ = 20802; + const constexpr size_t kINS_MSG_ = 20803; } -namespace udp +namespace protocal { - void loop(); + //以字节计算的每个包的大小和协议中每一部分的大小, 二级缩进的和应该等于第一级缩进 + const constexpr size_t kCLI_LOGIN_PACSIZE_ = 8; + const constexpr size_t kCLI_LOGIN_UID_ = 7; + const constexpr size_t kCLI_LOGIN_STATE_ = 1; - void recv(); - void send(); -} + const constexpr size_t kCENT_RESPONSE_PACSIZE_ = 4; + const constexpr size_t kMIR_BEAT_PACSIZE_ = 8; + const constexpr size_t kMIR_BEAT_IP_ = 4; + const constexpr size_t kMIR_BEAT_LOAD_ = 4; +} #endif //SRC_UDP_H - - /* class IP { diff --git a/include/center/MirDescript.h b/include/center/MirDescript.h index 390ee7a..1705a7a 100644 --- a/include/center/MirDescript.h +++ b/include/center/MirDescript.h @@ -3,38 +3,67 @@ #pragma once -#include "Telemeter.hpp" -#include "Udp.hpp" - #include -#include #include -class MirDescript : public boost::noncopyable +#include + +#include + + +using uuid = size_t; + +class MirDescript { - private: - uint8_t beat_; //心跳次数计数, 用于 - LoadLevel load_level_; //粗略描述负载情况 - DetailLoadState load_state_; //详细负载情况todo: memcpy(this_state, mir_descript.load_state_) - std::unordered_set cli_ips_; //当前负责的cli_ip为了O(1)查找 - std::vector load_cache_; //记录过去一段时间mir负载的缓冲 - - public: - static const constexpr int noexist = -1; - - public: - uint getBeat() const { return static_cast(beat_); } - void resetBeat(uint max_disbeat) { assert(max_disbeat <= 128), this->beat_ = max_disbeat; } - LoadLevel getRoughLoad() const { return this->load_level_; } - void setLoadState(DetailLoadState&& load) { copy(&(this->load_state_), &load); } - auto contains(IP cli_ip) { return auto index = this->cli_ips_.find(cli_ip), index == std::end(this->cli_ips_) ? noexist : index; } +private: + uint8_t beat_; //心跳次数计数, 用于 + LoadLevel load_level_; //粗略描述负载情况 + DetailLoadState load_state_; //详细负载情况todo: memcpy(this_state, mir_descript.load_state_) + std::unordered_set cli_ids_; //当前负责的cli_ip为了O(1)查找 + std::vector load_cache_; //记录过去一段时间mir负载的缓冲 +public: + static const constexpr int noexist = -1; -}; +public: + //mirdescrip只可能被默认创建后进行修改, 因此无其他构造函数 + MirDescript() + : beat_(telemeter::setting->mir_max_disbeat_time_), + load_level_(LoadLevel::untapped), + load_state_({0, 0, 0, RESERVE_SEGMENG_INIT_VALUE}), + cli_ids_(), + load_cache_() {} + + MirDescript(const MirDescript& md) + : beat_(md.beat_), + load_level_(md.load_level_), + load_state_(md.load_state_), + cli_ids_(md.cli_ids_), + load_cache_(md.load_cache_) {} + +public: + uint decre_and_get_beat() { beat_--; return static_cast(beat_); } + + void reset_beat(uint max_disbeat) { assert(max_disbeat <= 128), this->beat_ = max_disbeat; } + LoadLevel get_load_level() const { return this->load_level_; } + void set_load_level(LoadLevel ll) { this->load_level_ = ll; } + void set_detail_state(DetailLoadState&& load) { memcpy(&(this->load_state_), &load, sizeof(DetailLoadState)); } + bool contains(uuid cli_id) { return this->cli_ids_.find(cli_id) == std::end(this->cli_ids_) ? false : true; } + + void erase_cli(uuid cli_id) { this->cli_ids_.erase(cli_id); } + + std::vector get_dispatched_cli() { + std::vector ret {}; + ret.reserve(cli_ids_.size()); + for(auto cli_id : cli_ids_) + ret.push_back(cli_id); + return ret; + } +}; #endif //SRC_CENTER_MIRDESPCRIPT_H \ No newline at end of file diff --git a/include/center/TcpEcho.h b/include/center/TcpEcho.h index 7a9dab7..166fe38 100644 --- a/include/center/TcpEcho.h +++ b/include/center/TcpEcho.h @@ -1,24 +1,24 @@ #ifndef SRC_CENTER_TCPECHO_H #define SRC_CENTER_TCPECHO_H -#include "muduo/net/TcpServer.h" +#include class EchoServer { - public: - EchoServer(muduo::net::EventLoop* loop, - const muduo::net::InetAddress& listenAddr); +public: + EchoServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr); - void start(); // calls server_.start(); + void start(); // calls server_.start(); - private: - void onConnection(const muduo::net::TcpConnectionPtr& conn); +private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); - void onMessage(const muduo::net::TcpConnectionPtr& conn, - muduo::net::Buffer* buf, - muduo::Timestamp time); + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); - muduo::net::TcpServer server_; + muduo::net::TcpServer server_; }; #endif //SRC_CENTER_TCPECHO_H \ No newline at end of file diff --git a/include/center/center.h b/include/center/center.h index 9e6158e..22c2874 100644 --- a/include/center/center.h +++ b/include/center/center.h @@ -1,46 +1,66 @@ #ifndef SRC_CENTER_H #define SRC_CENTER_H -#include "muduo/base/ThreadPool.h" +#include "netinet/in.h" +#include "sys/socket.h" +#include "arpa/inet.h" -#include "Udp.hpp" -#include "Telemeter.hpp" -#include "../Type.hpp" //lock free queue -> lfqueue +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "MirDescript.h" +#include -#include +#include + +#include "MirDescript.h" class center { private: - //O(1)查找所有可用的mirip地址, [不再]初始化时从db中取出预存, [而是]从心跳包中分析即可, 心跳包最后一段表示当前连接数[处理mirror连接情况与center缓存数据不一致的问题] - //记录树形mir->cli信息的数据结构, list? hash_table?, 需要缓存mir负载信息以供调度算法使用? - //一种变量, 记录过去一段时间每个mir的平均负载情况, 定时更新到遥测数据库里 - using uuid = size_t; - std::set all_cli_; //查找频繁, 不从mirs_data中遍历, 额外保存 - std::unordered_map mirs_data_; //记录信息的树形结构 - lfqueue cookie_; //记录最近登陆过的cli缓冲 - muduo::ThreadPool pool_; //线程池 + std::set all_cli_; //查找频繁, 不从mirs_data中遍历, 额外保存 + std::unordered_map mirs_data_; //记录信息的树形结构 + + std::atomic atom_mutex_; //读写cookie的原子锁 + std::list cookie_; //记录最近登陆过的cli缓冲 + + muduo::ThreadPool pool_; //线程池 private: - //center start: + //读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 + void read_config(); - //读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 - void read_config(); + //开启监听cli登录的udp线程, 每隔几十次登录调用一次负载均衡分配算法更改当前的current_available_mir + void wait_cli_login(); - //开启监听cli登录的udp线程, 每隔几十次登录调用一次负载均衡分配算法更改当前的current_available_mir - void wait_cli_login(); + //开启收听mir心跳的udp线程, mir心跳断线的算法在这里实现, 记录最近一段时间遥测信息的算法也在这里, + void listen_mir_beat(); - //开启收听mir心跳的udp线程, mir心跳断线的算法在这里实现, 记录最近一段时间遥测信息的算法也在这里, - void listen_mir_beat(); + //定时清空登录信息, 默认时间每晚十二点 + void clear_mirs_data(); - //定时清空登录信息的算法, 例如每晚十二点, - void clear_mirs_data(); + //负载均衡算法, 返回当前能用的mir + IP load_balance(); public: - - void start(); + center() + : all_cli_(), + mirs_data_(), + atom_mutex_(false), + pool_() {}; + + center(const center& ) = delete; + + void start(); + + //崩溃时输出程序中当前全部信息到log中 + void log_info(std::exception& e, const char* crush_file); }; #endif //SRC_CENTER_H \ No newline at end of file diff --git a/include/center_head b/include/center_head new file mode 100644 index 0000000..c6103e0 --- /dev/null +++ b/include/center_head @@ -0,0 +1,3 @@ +#include "Center/center.h" +#include "Center/MirDescript.h" +#include "Center/TcpEcho.h" \ No newline at end of file diff --git a/include/common_head b/include/common_head new file mode 100644 index 0000000..b4e1b77 --- /dev/null +++ b/include/common_head @@ -0,0 +1,3 @@ +#include "Common/ServerBase.hpp" +#include "Common/Telemeter.hpp" +#include "Common/Udp.hpp" \ No newline at end of file diff --git a/include/db_control/db_control.cpp b/include/db_control/db_control.cpp index febb51f..85d2080 100644 --- a/include/db_control/db_control.cpp +++ b/include/db_control/db_control.cpp @@ -1,29 +1,53 @@ #pragma once #include -#include +#include "../mirror/lesson.hpp" +#include "../ServerBase.hpp" #include +#include "../mirror/ClassMes.hpp" +#include +#include -namespace db_control{ +namespace db_control { + + void check_week_and_day(nanodbc::connection conn, scu_date &date) { + if (date.day == 7) { + date.week += 1; + date.day = 1; + } else { + date.day += 1; + } + } /* - * param CCmap uuid->ClassInfo + * param CCmap uuid->ClassMes * param skjc 上课节次 * */ - void update_lesson_info(std::map &CCmap, unsigned skjc){ - - std::string date_stmt = std::string("select new_week, new_day from calendar"); - std::string find_stmt = std::string(""); - std::string week = "5"; - std::string day = "4"; - try{ -// 获取上课周与星期,及学校日历,主要涉及到补课需求 - nanodbc::result date_row = nanodbc::execute(conn, date_stmt); - week = date_row.get(0); - day = date_row.get(1); - - //补全find_stmt语句 + + void + query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, + scu_date *date, Uuid id = -1) { + size_t week = date->week; //第几周 + size_t day = date->day; //星期几 + bool new_client = false; + std::string find_stmt{}; + + std::string uuid_stmt{}; + + if (id < 0) { + auto iter = CCmap.begin(); + uuid_stmt += "( U.uuid = " + std::to_string(iter->first); + for (auto iter = CCmap.begin(); iter != CCmap.end(); iter++) { + uuid_stmt += " OR\n U.uuid = "; + uuid_stmt += std::to_string(iter->first); + } + uuid_stmt += ") AND\n" + } else { + uuid_stmt = std::string("U.uuid = " + std::to_string(id)); + new_client = true; + } + auto get_find_stmt = [&](size_t skJc) { find_stmt = std::string("SELECT\n" "U.uuid AS uuid,\n" "P.kch AS `kch`,\n" @@ -31,27 +55,60 @@ namespace db_control{ "K.kcm AS `kcm`,\n" "P.jsxm AS `jsxm`,\n" "P.jxdd AS `jdxx`,\n" + "p.jsszxqh AS `jsszxqh`\n" "FROM\n" "uuid_jxdd AS U\n" "INNER JOIN pksj AS P ON U.jxdd = P.jxdd AND U.jsszxqh = P.jsszxqh\n" "INNER JOIN kcb AS K ON P.kch = K.kch\n" "WHERE\n" - "P.sksj <= " + skjc.c_str() + " AND\n" - "P.sksj+P.cxjc\t >= " + skjc.c_str() +" AND\n" - "P.skxq = " + day.c_str() + " AND\n" - "SUBSTR(qsz," + week.c_str() + ",1)=\'1\'"); - //查询结果find_stmt - nanodbc::result find_row = nanodbc::execute(conn, find_stmt); - - for(; find_row.next(); ){ - std::string uuid = find_row.get(0); - lesson lesson = lesson(find_row.get(1),find_row.get(2),find_row.get(3),find_row.get(4),find_row.get(5)) - - CCmap.insert(std::make_pair(uuid, lesson)); + + uuid_stmt.c_str() + + "P.sksj <= " + skJc + " AND\n" + "P.sksj+P.cxjc\t >= " + skJc + " AND\n" + "P.skxq = " + day + " AND\n" + "SUBSTR(qsz," + + week + ",1)=\'1\'"); + }; + + auto update_map = [&](size_t jc, bool first, bool new_cli = false;) { + get_find_stmt(skjc); + try { + nanodbc::result find_row = nanodbc::execute(conn, find_stmt); + for (; find_row.next();) { + int uid = find_row.get(0); + + if (new_cli) { + int xqh = find_row.get(6); + std::string dd = find_row.get(5); + ClassPlace cp; + cp.jxdd_ = dd; + cp.jsszxqh = xqh; + ClassMes ci; + ci.classPlace_ = cp; + CCmap.insert(std::make_pair(id, ci)); + } + + if (CCmap.find(uid) != CCmap.end()) { + lesson les = lesson(find_row.get(1), find_row.get(2), + find_row.get(3), find_row.get(4), + find_row.get(5)); + if (first) + CCmap.at(uid).lesson_1 = les; + else + CCmap.at(uid).lesson_2 = les; + } else { + continue; + } + } + } catch (const std::exception &e) { + std::cerr << e.what() << std::endl; //更换为日志报错 } + }; - }catch(const std::exception& e){ -// 输出至日志 +// 更新当前节次 + update_map(skjc, true, new_client); + if (two_lesson) { +// 更新下一节次 + update_map(skjc + 1, false, new_client); } + } -} \ No newline at end of file diff --git a/include/json_control/json_control.cpp b/include/json_control/json_control.cpp new file mode 100644 index 0000000..665e574 --- /dev/null +++ b/include/json_control/json_control.cpp @@ -0,0 +1,103 @@ +#pragma once + +#include "../mirror/ClassMes.hpp" +#include +#include + +namespace json_control{ + +void getJson(rapidjson::Writer&writer, const Message& mes){ + //开启对象 + writer.StartObject(); + //title + writer.Key("Title"); + writer.String(mes.title.c_str()); + + //text + writer.Key("text"); + writer.String(mes.text.c_str()) + + //expiretime + writer.Key("expireTime"); + writer.String(mes.expireTime.c_str()); + + //结束对象 + writer.EndObject(); +} + +void getJson(rapidjson::Writer&writer, const lesson &les){ + //开始对象 + writer.StartObject(); + + //课程号 + writer.Key("kch"); + writer.String(les.kch_.c_str()); + + //课序号 + writer.Key("kxh"); + writer.Int(les.kxh_.c_str()) + + //课程名 + writer.Key("kcm"); + writer.String(les.kcm_.c_str()); + + //教师姓名 + writer.Key("jsxm"); + writer.String(les.jsxm_.c_str()); + + //教学地点 + writer.Key("jxdd"); + writer.String(les.jxdd_.c_str()); + + //结束对象 + writer.EndObject(); +} +void getJsonInfo(const ClassMes& mes, const muduo::Timestamp& timestamp) { + rapidjson::StringBuffer strBuf; + rapidjson::Writer writer(strBuf); + //声明strBuf与writer对象 + + //开启json对象 + writer.StartObject(); + + //时间戳 + writer.Key("time"); + writer.String(timestamp.toString().c_str()); + + //图像的url + writer.Key("image_url"); + writer.String(mes.image_url.c_str()); + + //消息队列 + writer.Key("message"); + //开启数组 + writer.StartArray(); + for (auto iter = mes.messages.begin(); iter != mes.messages.end(); iter++) { + getJson(writer, *iter); + } + //结束数组 + writer.EndArray(); + + //第一节课信息 + writer.Key("event"); + + getJson(writer, mes.lesson_1); + + //第二节课信息 + writer.Key("next_event"); + + getJson(writer, mes.lesson_2); + + //需要更新 + writer.Key("needUpdate"); + writer.Bool(true); + + //结束json对象 + writer.EndObject(); + + std::string json = strBuf.GetString(); + + return json; +} + +}//End namespace of json_control diff --git a/include/mirror/BackGround.hpp b/include/mirror/BackGround.hpp new file mode 100644 index 0000000..5fbab9a --- /dev/null +++ b/include/mirror/BackGround.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct BackGround{ + int PicId; + std::string PicCode; + std::string PicDes; + + BackGround(int id, const std::string& code,const std::string &des): PicId(id), PicCode(code), PicDes(des){}; +}; \ No newline at end of file diff --git a/include/mirror/ClassInfo.hpp b/include/mirror/ClassInfo.hpp deleted file mode 100644 index 2f52744..0000000 --- a/include/mirror/ClassInfo.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -//暂时以string代表课程信息 - -//classinfo中应该有一个bool量表示是否发送过, 发送过置否, 每次更新置真 - -struct ClassPlace final{ - std::string jsdd_; //教室地点 - unsigned jsszxqh; //教室所在校区号 -}; - -struct ClassInfo final{ - std::string jsdd_; //教师地点 - std::unordered_set lessons_; //课程信息 - bool status_; //true->已发送 -}; diff --git a/include/mirror/ClassMes.hpp b/include/mirror/ClassMes.hpp new file mode 100644 index 0000000..f3547b4 --- /dev/null +++ b/include/mirror/ClassMes.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +#include "Lesson.hpp" +#include "CliDescript.hpp" +#include "Message.hpp" + +struct ClassMes final{ + //ClassPlace classPlace_; //教室地点 暂不做内容发送 + Lesson lesson_1; //课程信息 + Lesson lesson_2; + std::string image_url; + std::deque messages; +}; diff --git a/include/mirror/Cli.cpp b/include/mirror/Cli.cpp deleted file mode 100644 index 3d49754..0000000 --- a/include/mirror/Cli.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by XM on 2021/5/16. -// - -#include "Cli.hpp" diff --git a/include/mirror/Cli.hpp b/include/mirror/Cli.hpp index cc3a5f2..03fbd77 100644 --- a/include/mirror/Cli.hpp +++ b/include/mirror/Cli.hpp @@ -1,15 +1,14 @@ // -// Created by XM on 2021/5/16. +// Created by XM on 2021/5/20. // -#pragma once - - -using Cli = std::string; - -// -//class cli{ -// -//}; +#pragma once +namespace Cli{ + using Uuid = unsigned int; +} +struct ClassPlace final{ + std::string jxdd_; //教室地点 + unsigned jsszxqh; //教室所在校区号 +}; diff --git a/include/mirror/CliDescript.hpp b/include/mirror/CliDescript.hpp new file mode 100644 index 0000000..0796290 --- /dev/null +++ b/include/mirror/CliDescript.hpp @@ -0,0 +1,22 @@ +// +// Created by XM on 2021/5/20. +// + +#pragma once + +#include + +namespace Cli{ + using Uuid = unsigned int; +} + +struct CliDes{ + Cli::Uuid id; + size_t campus; + std::string stamp; +}; + +struct ClassPlace final{ + std::string jxdd_; //教室地点 + unsigned int jsszxqh; //教室所在校区号 +}; diff --git a/include/mirror/Message.hpp b/include/mirror/Message.hpp index 27971b2..f8dc38d 100644 --- a/include/mirror/Message.hpp +++ b/include/mirror/Message.hpp @@ -1,24 +1,10 @@ #pragma once -#include "../Udp.hpp" +#include "CliDescript.hpp" -#include -#include -#include - -//暂时以string代表message的内容 -using Content = std::string; - -struct Content final{ - std::string time_; - std::string image_url; - std::string message_; - std::string event_; +struct Message{ + std::string title; + std::string text; + int expireTime;//seconds }; -class Message -{ - private: - Content content_; //消息内容 - std::unordered_set dest_; //需要收到消息的目标 -}; diff --git a/include/mirror/Mirror.cpp b/include/mirror/Mirror.cpp index 79ee01c..dcd2a27 100644 --- a/include/mirror/Mirror.cpp +++ b/include/mirror/Mirror.cpp @@ -1,4 +1,4 @@ -#include +#include "Mirror.hpp" void Mirror::start() { @@ -6,10 +6,13 @@ void Mirror::start() { pool_.setMaxQueueSize(30); //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 pool_.start(static_cast(2 * std::thread::hardware_concurrency())); - auto thd_start = [&](const char* info){ + auto thd_start = [&](const char *info) { std::clog << "thread start: " << info << std::endl; }; + // db_config 初始化 + nanodbc::connection conn = nanodbc::connection(db_dsn, db_name, db_passwd); + //读取配置文件 this->pool_.run([this]() { read_config(); }); thd_start("read config"); @@ -17,12 +20,8 @@ void Mirror::start() { this->pool_.run([this]() { update_data_info(); }); thd_start("update data info"); //更新数据缓存 - this->pool_.run([this]() { update_clis_data() }); - thd_start("updae clients data") - - //建立cli链接 - this->pool_.run([this]() { listen_cli_beat(); }); - thd_start("listen clients beat"); + this->pool_.run([this]() { update_clis_data(); }); + thd_start("updae clients data"); //输出日志 } @@ -34,7 +33,7 @@ void Mirror::read_config() { static std::ifstream in{config_file_path, std::ios::in}; Setting set{}; memset(&set, 0, sizeof(Setting)); - uint next_read_interval{0}; + size_t next_read_interval{0}; auto read_data = [&]() { if (!in.is_open()) @@ -47,15 +46,13 @@ void Mirror::read_config() { else if (line.find("next_read") != std::string::npos) next_read_interval = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); else if (line.find("mir_heart") != std::string::npos) - set.mir_load_record_interval_ = std::stoi( + set.mir_heart_beat_interval_ = std::stoi( std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); else if (line.find("mir_load") != std::string::npos) - set.mir_dblog_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + set.mir_load_report_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); else if (line.find("cli_class") != std::string::npos) - set.mir_max_disbeat_time_ = std::stoi( + set.cli_class_info_cache_time_ = std::stoi( std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - else if(line.find("class_interval") != std::string::bois) - set.class_interval_ = std::stoi( std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); } }; @@ -82,8 +79,11 @@ void Mirror::read_config() { void Mirror::update_data_info() { // 发送ip地址 - IP center_ip{0}; - IP this_ip{0}; + using Server::IP; + IP center_ip{0}; //通过配置文件 + IP this_ip{0};//unknown + + DetailLoadState dtlLoadState{}; // 定义计算服务器负载情况的函数 auto cal_ser_load = [&]() -> uint8_t { return 0; @@ -91,6 +91,8 @@ void Mirror::update_data_info() { // 定义计算内存负载情况的函数 auto cal_mem_load = [&]() -> uint8_t { + std::ifstream in; + std::string filename = ""; return 0; }; @@ -99,21 +101,34 @@ void Mirror::update_data_info() { return 0; }; - auto get_packet = [&](IP, DetailLoadState){ + auto get_packet = [&](IP, DetailLoadState DtlLoadState) { + center_ip; + this_ip; + //calculate ServerLoad + uint8_t serverLoad = cal_ser_load(); + DtlLoadState.serve_load = serverLoad; + //calculate MemoryLoad + uint8_t memLoad = cal_mem_load(); + DtlLoadState.mem_load = memLoad; + //calculate NetworkLoad + uint8_t netLoad = cal_net_load(); + DtlLoadState.net_load_ = netLoad; + return "12345678"; }; - DetailLoadState dtlLoadState{}; + + struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; // 设置发送端口 - servaddr.sin_port = htons(myport); + servaddr.sin_port = htons(port::kMIR_BEAT_); // 设置发送ip - servaddr.sin_addr.s_addr = inet_addr(serverip); + servaddr.sin_addr.s_addr = inet_addr(center_ip); // 发送缓存 - char* packet = "\0"; + char *packet = "\0"; // 更新间隔 size_t time = 60; @@ -123,67 +138,59 @@ void Mirror::update_data_info() { //线程主循环 while (true) { - if (time == mir_load_report_interval) { - this_ip; - //calculate ServerLoad - uint8_t serverLoad = cal_ser_load(); - dtlLoadState.serve_load = serverLoad; - //calculate MemoryLoad - uint8_t memLoad = cal_mem_load(); - dtlLoadState.mem_load = memLoad; - //calculate NetworkLoad - uint8_t netLoad = cal_net_load(); - dtlLoadState.net_load_ = netLoad; - - //to_string(8byte) = 4+1+1+1+1 true/false - get_packet(this_ip, dtlLoadState); - time = 1; - } - - if(time == 1){ - get_packet(this_ip, dtlLoadState); + if (time == telemeter::setting->mir_load_report_interval_) { + //to_string(8byte) = 4+1+1+1+1 true/false + //更新负载情况 + send_buf = get_packet(this_ip, dtlLoadState); + time = 1; } + // 发送‘心跳包’ sendto(sock, sendbuf, strlen(sendbuf), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); - // 重置缓冲 memset(sendbuf, 0, sizeof(sendbuf)); -// - sleep(setting.mir_heart_beat_interval * 1000); - + // 统计发送心跳包次数 time++; + //心跳包频率 + sleep(telemeter::setting->mir_heart_beat_interval * 1000); } } -//多并发 -void Mirror::listen_cli_beat() { - //set server.onConnect 连接函数 - - //set server.onMessage 接收消息函数(回复消息) - - //set server - - while (true) { - server_; - //接收消息 - - //获取time(为null则加入cli_tree) -// -// if(第一次Content) { -// 返回第一次Content -// }else{ -// 分析时间戳 -// if(版本相同){ -// 返回不需要更新 -// }else{ //版本不同 -// 获取Content -// 返回Content -// } -// } +//待修改 +void Mirror::on_message(muduo::net::TcpConnectionPtr conn, + std::string msg, + muduo::Timestamp time) { + //比较时间戳, 相等, 无事发生 + if (equal(time, *this->wj_timestamp_) { + //发送不需要更新的json + conn->send(CliDescript::NO_NEED_UPDATE); + } else //这里的逻辑需要完善 + { + //回复的内容 + JsonValue reply(); + //解析msg, 得到uuid + JsonValue pack = JsonParser(msg); + Uuid id = pack["uuid"]; + //查询有无即时消息 + if (message_.front().get_dests().contains(id)); + { + reply["Message"] = message_.front().to_string(); + } + } +} - } +//多并发 +void Mirror::listen_cli_beat(muduo::net::TcpConnectionPtr &conn, + muduo::net::Buffer *buf, + muduo::Timestamp time) { + //set server.onConnect 连接函数 + this->pool_.run(std::bind(Mirror::on_message, + this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3), + std::move(conn), + std::move(std::string(buf->retrieveAllAsString())), + std::move(time))); } //监听center发送的udp包 @@ -191,46 +198,211 @@ void Mirror::listen_mes() { // udp while (true) { //server.start + + //接收到包 + + //数据库拉取信息 + + //更新信息 } } //清除mirror->client树信息 void Mirror::clear_cli_data() { while (true) { + //每日0点更新.用scu_time更新 + //sleep()24h } } +//定时拉取数据库信息, 更新时间戳 void Mirror::update_clis_data() { -// db_config 初始化 - const std::string dsn = ""; - const std::string name = ""; - const std::string passwd = ""; - nanodbc::connection conn = nanodbc::connection(dsn, name, passwd); + //cli-classinfo缓存 + std::unordered_map clis_data; - while (true) { - for(size_t i = 1; i <= 4; i++) { - db_control::update_lesson_info(conn, this->cli_lesson_, i); - sleep(class_interval * 60 * 1000) - } +// 校园日历 + scu_date sD{1, 1}; + scu_date sD_1{1, 1}; + scu_date *scuDate = &sD; + scu_date *scuDate_copy = &sD_1; - time_sleep_until();//直到每日13:00 + scu_date scuDate_cache{}; - for(size_t i = 5; i <= 9; i++){ - db_control::update_lesson_info(conn, this->cli_lesson_, i); - sleep(class_interval * 60 * 1000) - } + scu_time nowTime{0, 0}; - time_sleep_until();//直到每日19:00 + auto swap_scu_date_ptr = [&]() { + scu_date *tmp = scuDate; + scuDate_copy = scuDate; + scuDate = tmp; + }; + +//写当日date(其实不会出现冲突.但为以后消费者模型做准备工作) + auto update_scu_date = [&]() { +//更新当日上课信息 + db_control::check_week_and_day(conn, scuDate_cache); +//复制至副本 + memcpy(scuDate_copy, &scuDate_cache, sizeof(scu_date)); +//交换指针 + swap_scu_date_ptr(); + }; - for(size_t i = 10; i <= 12; i++){ - db_control::update_lesson_info(conn, this->cli_lesson_, i); - sleep(class_interval * 60 * 1000) +// 判断时间 + auto at_middle = [&](const scu_time &lTime, const scu_time &rTime) { + return (lTime <= nowTime) && (nowTime < rTime); + }; + + auto get_seconds_from_now = [&](const scu_time &time) { + nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + + auto query_scu_time = [&](int &xqh, int &jc) -> scu_time { +// 获取迭代器,遍历时间表 + + auto iter1 = this->wj_Time.begin(); + auto iter2 = this->ja_Time.begin(); +// 上课节次,用于返回 + int skjc = 0; + + nowTime = scu_time::toScutime(muduo::Timestamp::now());//获取当前时间,进行分析 + + for (; iter1 != wj_Time.end(); iter1++, iter2++) { + skjc++; + jc = skjc; + if (skjc <= 4) { + if (nowTime <= *iter1) { + xqh = 1; + return scu_time(0, 15); + } else { + if (nowTime <= *iter2) { + xqh = 3; + if (skjc == 4) + return scu_time(2, 40); + else + return scu_time(0, 40); + } else { + continue; + } + } + } else { + if (nowTime <= *iter2) { + xqh = 3; + return scu_time(0, 10); + } else { + if (nowTime <= *iter1) { + xqh = 1; + if (skjc == 9) //晚餐 + return scu_time(1, 30); + else if (skjc == 7) + return scu_time(0, 55); + else if (skjc == 12) + return scu_time(0, 0); + else + return scu_time(0, 45); + } else { + continue; + } + } + } + } + }; + +// 自动计算当前时间 + auto query_clis_data = [&, this]() { + std::unordered_map clis_data_cache_; + bool two_lessons = true; + int xqh = 0; //校区号 + int jc = 0; //时间 + + auto update_uC_map = [](const std::unordered_map &data_map, + std::unordered_map *origin_map, + std::unordered_map *copy_map) { + //赋值 + *copy_map = data_map; +// 交换指针 + auto tmp = copy_map; + copy_map = origin_map; + origin_map = tmp; + }; + + + //获取应当更新的校区号与节次 + scu_time wait_time = query_scu_time(xqh, jc); + + if (jc == 4 || jc == 9 || jc == 12) + two_lessons = false; + size_t wait_second = wait_time.toSeconds(); + if (xqh == 1) { +// 更新值 +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + clis_data_cache_ = *(this->wj_clis_data_); +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); +// 获取当前时间戳 + muduo::Timestamp nTime = muduo::Timestamp::now(); +// 更新时间戳 + update_timestamp(nTime, wj_timestamp_, wj_timestamp_copy); + // 交换指针 + + update_uC_map(clis_data_cache_, this->wj_clis_data_, this->wj_clis_data_copy); + } else if (xqh == 3) { +// 更新值 + clis_data_cache_ = *ja_clis_data_; +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); +// 获取当前时间戳 + muduo::Timestamp nTime = muduo::Timestamp::now(); +// 更新时间戳 + update_timestamp(nTime, ja_timestamp_, ja_timestamp_copy); +// 交换指针 + update_uC_map(clis_data_cache_, this->ja_clis_data_, this->ja_clis_data_copy); } - time_sleep_until(); //直到每日7:30 + return wait_second; + }; + +// mirror开机时,初始化当时时间 + update_scu_date(); + muduo::Timestamp nTime = muduo::Timestamp::now(); + nowTime = scu_time::toScutime(nTime); + + +// 进入任务线程阶段 + while (true) { +// 挂起. 7.55唤醒 + sleep(get_seconds_from_now(scu_time(7, 55)) * 1000); + + while (true) { + nowTime = scu_time::toScutime(muduo::Timestamp::now());//记录当前时间 + size_t sleepSeconds = 0; + sleepSeconds = query_clis_data(); //更新数据,在函数体内自动计算时间 + + if (sleepSeconds == 0) + break; + //休眠至下一次更新 + sleep(sleepSeconds * 1000); + } + sleep(get_seconds_from_now(scu_time(24, 0)) * 1000); //沉睡至24点 +// 24点更新当日上课信息 + update_scu_date(); } + + conn.close(); } +void Mirror::update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, + muduo::Timestamp *copy_campus_stamp) { + + // 赋值 + *copy_campus_stamp = dataStamp; +// 交换指针 + auto swap = [](muduo::Timestamp *origin, muduo::Timestamp *copy) { + muduo::Timestamp *tmp = origin; + origin = copy; + copy = tmp; + }; + swap(origin_campus_stamp, copy_campus_stamp); +} diff --git a/include/mirror/Mirror.hpp b/include/mirror/Mirror.hpp index 12a071d..acc2b27 100644 --- a/include/mirror/Mirror.hpp +++ b/include/mirror/Mirror.hpp @@ -1,62 +1,148 @@ #ifndef SRC_MIRROR_H #define SRC_MIRROR_H -#include "muduo/base/ThreadPool.h" -#include "muduo/net/InetAddress.h" -#include "muduo/net/TcpServer.h" -#include "muduo/net/EventLoop.h" +#pragma once -#include "../Telemeter.hpp" -#include "../Type.hpp" //lock free queue -> lfqueue +#include +#include +#include +#include +#include +#include -#include "ClassInfo.hpp" -#include "Message.hpp" +//udp使用 +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include -#include -class Mirror -{ - private: - DetailLoadState load_; - std::queue messages_; - std::unordered_map clis_data_; //uuid->info - lfqueue> cookie_; - std::map cli_lesson_; - nanodbc::connection conn; +#include +#include +#include +#include +#include + +#include + + +#include "ClassMes.hpp" + +using Cli::Uuid; + +class Mirror final { + + struct OldHash { + size_t msg_, course_, event_, next_event_; + + bool operator==(const OldHash &x) { + return this->course_ == x.course_ + && this->event_ == x.event_ + && this->msg_ == x.event_ + && this->next_event_ == x.next_event_; + //最后一位暂时不做比较 + } + } + +private: + + //停用内存相关与timestamp + /* + std::unordered_map *wj_clis_data_ = new std::unordered_map; //uuid->info + std::unordered_map *wj_clis_data_copy = new std::unordered_map; //uuid->info + std::unordered_map *ja_clis_data_ = new std::unordered_map; //uuid->info + std::unordered_map *ja_clis_data_copy = new std::unordered_map; //uuid->info + + muduo::Timestamp *wj_timestamp_ = nullptr; + muduo::Timestamp *wj_timestamp_copy = nullptr; + muduo::Timestamp *ja_timestamp_ = nullptr; + muduo::Timestamp *ja_timestamp_copy = nullptr; + */ - muduo::net::EventLoop loop_; - muduo::net::TcpServer server_; - muduo::ThreadPool pool_; + std::unordered_map Class2Campus; + std::unordered_map cli_info_; + +// 数据库连接 + nanodbc::connection conn; +// 线程池 + muduo::ThreadPool pool_; // 数据库配置相关,仅在程序开始时使用 - const std::string db_dsn = "MariaDB-server"; - const std::string db_name = "root"; - const std::string db_passwd = "root"; +// 在配置文件获取 + const std::string db_dsn = "MariaDB-server"; + const std::string db_name = "root"; + const std::string db_passwd = "root"; + + std::string img_path = "/home/jol"; + + //配置文件 + std::vector wj_Time = { + scu_time(8, 0), scu_time(8, 55), scu_time(10, 0), + scu_time(10, 55), scu_time(14, 0), scu_time(14, 55), + scu_time(15, 30), scu_time(16, 55), scu_time(17, 50), + scu_time(19, 30), scu_time(20, 25), scu_time(21, 20) + }; + + std::vector ja_Time = { + scu_time(8, 15), scu_time(9, 10), scu_time(10, 15), + scu_time(11, 10), scu_time(13, 50), scu_time(14, 45), + scu_time(15, 40), scu_time(16, 45), scu_time(17, 40), + scu_time(19, 20), scu_time(20, 15), scu_time(21, 10) + }; + private: //mirror start: - //定时清空IP信息的算法, 例如每晚十二点, - void clear_cli_data(); +//Center相关 - //读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 + //更新load情况 Task2,udp信息 + void update_data_info(); + +// 自我更新相关 + //更新数据库 Task3 + //暂停该函数 + /* + void update_clis_data(); //定时更新wj_clis_data 和 ja_clis_data + */ + + //定时读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 Task4 void read_config(); - //更新load情况 - void update_data_info(); + //定时清空IP信息的算法, 例如每晚十二点, Task5 + void clear_cli_data(); + + //定时 更新图片与内存信息 + void update_pictures_info(); - //开启收听mir心跳的udp线程, mir心跳断线的算法在这里实现, 记录最近一段时间遥测信息的算法也在这里, + //Client相关 void listen_cli_beat(); - //等待即时消息 - void listen_mes(); - //更新数据库 - void update_clis_data(); + //回调查询信息 + static void on_message(const muduo::net::TcpConnectionPtr &conn, + muduo::net::Buffer *msg, + muduo::Timestamp time); + + + static void on_disconnected(); + + void update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, + muduo::Timestamp *copy_campus_stamp); + +//配置文件,初始化等 + void init(); public: + + //start开始读取配置文件 void start(); + Mirror() = default; }; #endif //SRC_MIRROR_H \ No newline at end of file diff --git a/include/mirror/MirrorConfig.txt b/include/mirror/MirrorConfig.txt index 21780aa..8f88194 100644 --- a/include/mirror/MirrorConfig.txt +++ b/include/mirror/MirrorConfig.txt @@ -2,7 +2,8 @@ next_read_interval: [600]s //多少秒之后重新读取配置文件, 需要不 mir_heart_beat_interval: [1]s //心跳的间隔 mir_load_report_interval: [60] //多少个心跳包后更新负载情况 cli_class_info_cache_time: [600]s //课程信息在cli断联后缓存时间, 如果内存紧张可以适当缩短 -class_interval: [55]min + + mir启动流程 启动EventLoop, 启动Server, 清空clis_data @@ -14,6 +15,7 @@ mir启动流程 cli通过tcp连接 ->连接:从cookie中寻找缓存, 若无则在clis_data中更新其信息, 从数据库拉取课表信息, 并根据课表信息提交一段时间后重新拉取下节课的任务 + ->查询:目前是多线程操作,单查询比联合查询效率更高(可详细测试),且消耗内存更少.故先查询所在校区号与教室地点.再利用该数据查询课程内容与下节课内容 ->断线:将clis_data的信息存入缓存, 设置 Message 使用者通过管理程序向数据库中插入即时消息的内容和目的地, 然后发送一个简短报文给center, center收到后 diff --git a/include/mirror/Util.hpp b/include/mirror/Util.hpp new file mode 100644 index 0000000..fa47122 --- /dev/null +++ b/include/mirror/Util.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + + +namespace db_control { + using Cli::Uuid; + + void check_week_and_day(nanodbc::connection conn, scu_date &date); + + /* + * param CCmap uuid->ClassMes + * param skjc 上课节次 + * + */ + void + query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, + scu_date *date, Uuid id = -1); + + + void query_background(nanodbc::connection conn, std::vector& backgrounds); + + void update_pic_info(nanodbc::connection conn, wj_clis_cache, const std::string &stamp); + + std::string find_pic(const nanodbc::connection &conn, Cli::Uuid id, const std::string &stamp); + + std::deque find_mes(const nanodbc::connection &conn, Cli::Uuid id, const std::string stamp); + + Lesson find_lesson(const nanodbc::connection &conn, Cli::Uuid, const std::string& stamp); +} + + +namespace json_control { + + void getJson(rapidjson::Writer &writer, const Message &mes); + + void getJson(rapidjson::Writer &writer, const Lesson &les); + + std::string getJsonInfo(const ClassMes &mes, const muduo::Timestamp ×tamp); + + void getIdAndStamp(const std::string& src, Cli::Uuid &id, std::string& stamp); +}//End namespace of json_control + +namespace codec{ + void downPic( const std::string &code,const std::string& path); + +} \ No newline at end of file diff --git a/include/mirror/lesson.hpp b/include/mirror/lesson.hpp index 0d0eed8..b934dcd 100644 --- a/include/mirror/lesson.hpp +++ b/include/mirror/lesson.hpp @@ -1,22 +1,21 @@ #pragma once + #include //#include -struct lesson final{ - std::string kch_; //课程号 - int kxh_; //课序号 - std::string kcm_; //课程名 - std::string jsxm_; //教师姓名 - std::string jxdd_; //教学地点 +struct Lesson final { + std::string kch_{""}; //课程号 + int kxh_{0}; //课序号 + std::string kcm_{""}; //课程名 + std::string jsxm_{""}; //教师姓名 + std::string jxdd_{""}; //教学地点 // JsonValue get_Event(); - lesson( std::string kch, unsigned short kxh, std::string kcm, std::string jsxm,std::string jxdd): + Lesson(std::string kch, unsigned short kxh, std::string kcm, std::string jsxm, std::string jxdd) : kch_(kch), kxh_(kxh), kcm_(kcm), jsxm_(jsxm), jxdd_(jxdd) {} - friend std::ostream& operator<<(std::ostream& out, const lesson& l){ - out << "kch: " << l.kch_ << ", kxh: " << l.kxh_ << ", kcm: " << l.kcm_ << ", jsxm: " << l.jsxm_ << ", jxdd: " << l.jxdd_; - return out; - } + Lesson() {} + }; \ No newline at end of file diff --git a/include/mirror_head b/include/mirror_head new file mode 100644 index 0000000..93dc092 --- /dev/null +++ b/include/mirror_head @@ -0,0 +1,7 @@ +#include "Mirror/ClassMes.hpp" +#include "Mirror/CliDescript.hpp" +#include "Mirror/Lesson.hpp" +#include "Mirror/Message.hpp" +#include "Mirror/Mirror.hpp" +#include "Mirror/Util.hpp" +#include "Mirror/BackGround.hpp" \ No newline at end of file From e26770a0dc8ba52e66798c3a3f9aae9b6326f0fc Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 Date: Tue, 8 Jun 2021 17:15:11 +0800 Subject: [PATCH 12/16] center has something wrong --- CMakeLists.txt | 2 +- Src/Center/Center.cpp | 64 +- Src/Common/ServerBase.cpp | 4 + Src/Mirror/Mirror.cpp | 630 ++++++++++++------ Src/Mirror/MirrorMain.cpp | 6 +- Src/Mirror/codec_lib.cpp | 4 +- Src/Mirror/db_lib.cpp | 151 ++++- Src/Mirror/json_lib.cpp | 4 +- include/Common/ServerBase.hpp | 5 +- include/Common/Telemeter.hpp | 24 +- include/Common/Udp.hpp | 42 +- include/ServerBase.cpp | 57 -- include/ServerBase.hpp | 45 -- include/Telemeter.hpp | 119 ---- include/Udp.hpp | 65 -- include/boost/any.hpp | 342 ---------- include/center/CenterConfig.txt | 48 -- include/center/MirDescript.cpp | 0 include/center/TcpEcho.cpp | 40 -- include/center/center.cpp | 84 --- include/center/center.h | 3 +- include/center/main.cpp | 22 - include/center_head | 2 + include/common_head | 2 + include/db_control/db_control.cpp | 114 ---- include/json_control/json_control.cpp | 103 --- include/mirror/Cli.hpp | 14 - include/mirror/CliDescript.hpp | 2 +- include/mirror/Message.hpp | 16 +- include/mirror/Mirror.cpp | 408 ------------ include/mirror/Mirror.hpp | 41 +- include/mirror/MirrorConfig.txt | 24 - include/mirror/Util.hpp | 27 +- include/mirror/lesson.hpp | 17 +- include/mirror_head | 4 +- include/muduo/base/AsyncLogging.cc | 136 ---- include/muduo/base/AsyncLogging.h | 77 --- include/muduo/base/Atomic.h | 97 --- include/muduo/base/BUILD.bazel | 23 - include/muduo/base/BlockingQueue.h | 72 -- include/muduo/base/BoundedBlockingQueue.h | 101 --- include/muduo/base/CMakeLists.txt | 34 - include/muduo/base/Condition.cc | 26 - include/muduo/base/Condition.h | 56 -- include/muduo/base/CountDownLatch.cc | 41 -- include/muduo/base/CountDownLatch.h | 34 - include/muduo/base/CurrentThread.cc | 77 --- include/muduo/base/CurrentThread.h | 54 -- include/muduo/base/Date.cc | 76 --- include/muduo/base/Date.h | 119 ---- include/muduo/base/Exception.cc | 18 - include/muduo/base/Exception.h | 40 -- include/muduo/base/FileUtil.cc | 181 ----- include/muduo/base/FileUtil.h | 89 --- include/muduo/base/GzipFile.h | 89 --- include/muduo/base/LogFile.cc | 133 ---- include/muduo/base/LogFile.h | 58 -- include/muduo/base/LogStream.cc | 342 ---------- include/muduo/base/LogStream.h | 203 ------ include/muduo/base/Logging.cc | 227 ------- include/muduo/base/Logging.h | 159 ----- include/muduo/base/Mutex.h | 233 ------- include/muduo/base/ProcessInfo.cc | 246 ------- include/muduo/base/ProcessInfo.h | 68 -- include/muduo/base/Singleton.h | 77 --- include/muduo/base/StringPiece.h | 189 ------ include/muduo/base/Thread.cc | 200 ------ include/muduo/base/Thread.h | 54 -- include/muduo/base/ThreadLocal.h | 59 -- include/muduo/base/ThreadLocalSingleton.h | 82 --- include/muduo/base/ThreadPool.cc | 156 ----- include/muduo/base/ThreadPool.h | 67 -- include/muduo/base/TimeZone.cc | 363 ---------- include/muduo/base/TimeZone.h | 52 -- include/muduo/base/Timestamp.cc | 62 -- include/muduo/base/Timestamp.h | 123 ---- include/muduo/base/Types.h | 123 ---- include/muduo/base/WeakCallback.h | 65 -- include/muduo/base/copyable.h | 19 - include/muduo/base/noncopyable.h | 20 - include/muduo/base/tests/AsyncLogging_test.cc | 64 -- include/muduo/base/tests/Atomic_unittest.cc | 38 -- .../muduo/base/tests/BlockingQueue_bench.cc | 106 --- .../muduo/base/tests/BlockingQueue_test.cc | 106 --- .../base/tests/BoundedBlockingQueue_test.cc | 110 --- include/muduo/base/tests/CMakeLists.txt | 86 --- include/muduo/base/tests/Date_unittest.cc | 88 --- include/muduo/base/tests/Exception_test.cc | 51 -- include/muduo/base/tests/FileUtil_test.cc | 30 - include/muduo/base/tests/Fork_test.cc | 46 -- include/muduo/base/tests/GzipFile_test.cc | 54 -- include/muduo/base/tests/LogFile_test.cc | 34 - include/muduo/base/tests/LogStream_bench.cc | 82 --- include/muduo/base/tests/LogStream_test.cc | 286 -------- include/muduo/base/tests/Logging_test.cc | 122 ---- include/muduo/base/tests/Mutex_test.cc | 82 --- include/muduo/base/tests/ProcessInfo_test.cc | 17 - .../base/tests/SingletonThreadLocal_test.cc | 58 -- include/muduo/base/tests/Singleton_test.cc | 65 -- .../base/tests/ThreadLocalSingleton_test.cc | 58 -- include/muduo/base/tests/ThreadLocal_test.cc | 61 -- include/muduo/base/tests/ThreadPool_test.cc | 97 --- include/muduo/base/tests/Thread_bench.cc | 86 --- include/muduo/base/tests/Thread_test.cc | 91 --- include/muduo/base/tests/TimeZone_unittest.cc | 276 -------- .../muduo/base/tests/Timestamp_unittest.cc | 66 -- include/muduo/net/Acceptor.cc | 89 --- include/muduo/net/Acceptor.h | 63 -- include/muduo/net/BUILD.bazel | 51 -- include/muduo/net/Buffer.cc | 58 -- include/muduo/net/Buffer.h | 422 ------------ include/muduo/net/CMakeLists.txt | 69 -- include/muduo/net/Callbacks.h | 82 --- include/muduo/net/Channel.cc | 146 ---- include/muduo/net/Channel.h | 113 ---- include/muduo/net/Connector.cc | 226 ------- include/muduo/net/Connector.h | 74 -- include/muduo/net/Endian.h | 65 -- include/muduo/net/EventLoop.cc | 278 -------- include/muduo/net/EventLoop.h | 166 ----- include/muduo/net/EventLoopThread.cc | 77 --- include/muduo/net/EventLoopThread.h | 50 -- include/muduo/net/EventLoopThreadPool.cc | 97 --- include/muduo/net/EventLoopThreadPool.h | 69 -- include/muduo/net/InetAddress.cc | 149 ----- include/muduo/net/InetAddress.h | 86 --- include/muduo/net/Poller.cc | 29 - include/muduo/net/Poller.h | 71 -- include/muduo/net/Socket.cc | 128 ---- include/muduo/net/Socket.h | 89 --- include/muduo/net/SocketsOps.cc | 316 --------- include/muduo/net/SocketsOps.h | 64 -- include/muduo/net/TcpClient.cc | 181 ----- include/muduo/net/TcpClient.h | 90 --- include/muduo/net/TcpConnection.cc | 429 ------------ include/muduo/net/TcpConnection.h | 161 ----- include/muduo/net/TcpServer.cc | 118 ---- include/muduo/net/TcpServer.h | 120 ---- include/muduo/net/Timer.cc | 26 - include/muduo/net/Timer.h | 63 -- include/muduo/net/TimerId.h | 53 -- include/muduo/net/TimerQueue.cc | 260 -------- include/muduo/net/TimerQueue.h | 86 --- include/muduo/net/ZlibStream.h | 145 ---- include/muduo/net/boilerplate.cc | 15 - include/muduo/net/boilerplate.h | 32 - include/muduo/net/http/BUILD.bazel | 9 - include/muduo/net/http/CMakeLists.txt | 30 - include/muduo/net/http/HttpContext.cc | 118 ---- include/muduo/net/http/HttpContext.h | 72 -- include/muduo/net/http/HttpRequest.h | 187 ------ include/muduo/net/http/HttpResponse.cc | 47 -- include/muduo/net/http/HttpResponse.h | 79 --- include/muduo/net/http/HttpServer.cc | 100 --- include/muduo/net/http/HttpServer.h | 68 -- .../net/http/tests/HttpRequest_unittest.cc | 79 --- .../muduo/net/http/tests/HttpServer_test.cc | 150 ----- include/muduo/net/inspect/BUILD.bazel | 9 - include/muduo/net/inspect/CMakeLists.txt | 26 - include/muduo/net/inspect/Inspector.cc | 383 ----------- include/muduo/net/inspect/Inspector.h | 67 -- .../muduo/net/inspect/PerformanceInspector.cc | 106 --- .../muduo/net/inspect/PerformanceInspector.h | 40 -- include/muduo/net/inspect/ProcessInspector.cc | 239 ------- include/muduo/net/inspect/ProcessInspector.h | 38 -- include/muduo/net/inspect/SystemInspector.cc | 132 ---- include/muduo/net/inspect/SystemInspector.h | 37 - include/muduo/net/inspect/tests/BUILD.bazel | 7 - .../muduo/net/inspect/tests/Inspector_test.cc | 15 - include/muduo/net/poller/DefaultPoller.cc | 27 - include/muduo/net/poller/EPollPoller.cc | 208 ------ include/muduo/net/poller/EPollPoller.h | 55 -- include/muduo/net/poller/PollPoller.cc | 141 ---- include/muduo/net/poller/PollPoller.h | 49 -- include/muduo/net/protobuf/BufferStream.h | 56 -- include/muduo/net/protobuf/CMakeLists.txt | 15 - .../muduo/net/protobuf/ProtobufCodecLite.cc | 243 ------- .../muduo/net/protobuf/ProtobufCodecLite.h | 192 ------ include/muduo/net/protorpc/CMakeLists.txt | 42 -- include/muduo/net/protorpc/README | 5 - include/muduo/net/protorpc/RpcChannel.cc | 184 ----- include/muduo/net/protorpc/RpcChannel.h | 152 ----- include/muduo/net/protorpc/RpcCodec.cc | 37 - include/muduo/net/protorpc/RpcCodec.h | 45 -- include/muduo/net/protorpc/RpcCodec_test.cc | 81 --- include/muduo/net/protorpc/RpcServer.cc | 68 -- include/muduo/net/protorpc/RpcServer.h | 57 -- include/muduo/net/protorpc/google-inl.h | 84 --- include/muduo/net/protorpc/rpc.proto | 36 - include/muduo/net/protorpc/rpcservice.proto | 44 -- include/muduo/net/tests/Buffer_unittest.cc | 170 ----- include/muduo/net/tests/CMakeLists.txt | 48 -- include/muduo/net/tests/Channel_test.cc | 112 ---- .../muduo/net/tests/EchoClient_unittest.cc | 114 ---- .../muduo/net/tests/EchoServer_unittest.cc | 86 --- .../net/tests/EventLoopThreadPool_unittest.cc | 68 -- .../net/tests/EventLoopThread_unittest.cc | 48 -- include/muduo/net/tests/EventLoop_unittest.cc | 42 -- .../muduo/net/tests/InetAddress_unittest.cc | 70 -- include/muduo/net/tests/TcpClient_reg1.cc | 29 - include/muduo/net/tests/TcpClient_reg2.cc | 30 - include/muduo/net/tests/TcpClient_reg3.cc | 24 - .../muduo/net/tests/TimerQueue_unittest.cc | 66 -- .../muduo/net/tests/ZlibStream_unittest.cc | 91 --- step.md | 102 +++ test_driver/client_bootstrap.csc | 14 +- 206 files changed, 861 insertions(+), 18633 deletions(-) delete mode 100644 include/ServerBase.cpp delete mode 100644 include/ServerBase.hpp delete mode 100644 include/Telemeter.hpp delete mode 100644 include/Udp.hpp delete mode 100644 include/boost/any.hpp delete mode 100644 include/center/CenterConfig.txt delete mode 100644 include/center/MirDescript.cpp delete mode 100644 include/center/TcpEcho.cpp delete mode 100644 include/center/center.cpp delete mode 100644 include/center/main.cpp delete mode 100644 include/db_control/db_control.cpp delete mode 100644 include/json_control/json_control.cpp delete mode 100644 include/mirror/Cli.hpp delete mode 100644 include/mirror/Mirror.cpp delete mode 100644 include/mirror/MirrorConfig.txt delete mode 100644 include/muduo/base/AsyncLogging.cc delete mode 100644 include/muduo/base/AsyncLogging.h delete mode 100644 include/muduo/base/Atomic.h delete mode 100644 include/muduo/base/BUILD.bazel delete mode 100644 include/muduo/base/BlockingQueue.h delete mode 100644 include/muduo/base/BoundedBlockingQueue.h delete mode 100644 include/muduo/base/CMakeLists.txt delete mode 100644 include/muduo/base/Condition.cc delete mode 100644 include/muduo/base/Condition.h delete mode 100644 include/muduo/base/CountDownLatch.cc delete mode 100644 include/muduo/base/CountDownLatch.h delete mode 100644 include/muduo/base/CurrentThread.cc delete mode 100644 include/muduo/base/CurrentThread.h delete mode 100644 include/muduo/base/Date.cc delete mode 100644 include/muduo/base/Date.h delete mode 100644 include/muduo/base/Exception.cc delete mode 100644 include/muduo/base/Exception.h delete mode 100644 include/muduo/base/FileUtil.cc delete mode 100644 include/muduo/base/FileUtil.h delete mode 100644 include/muduo/base/GzipFile.h delete mode 100644 include/muduo/base/LogFile.cc delete mode 100644 include/muduo/base/LogFile.h delete mode 100644 include/muduo/base/LogStream.cc delete mode 100644 include/muduo/base/LogStream.h delete mode 100644 include/muduo/base/Logging.cc delete mode 100644 include/muduo/base/Logging.h delete mode 100644 include/muduo/base/Mutex.h delete mode 100644 include/muduo/base/ProcessInfo.cc delete mode 100644 include/muduo/base/ProcessInfo.h delete mode 100644 include/muduo/base/Singleton.h delete mode 100644 include/muduo/base/StringPiece.h delete mode 100644 include/muduo/base/Thread.cc delete mode 100644 include/muduo/base/Thread.h delete mode 100644 include/muduo/base/ThreadLocal.h delete mode 100644 include/muduo/base/ThreadLocalSingleton.h delete mode 100644 include/muduo/base/ThreadPool.cc delete mode 100644 include/muduo/base/ThreadPool.h delete mode 100644 include/muduo/base/TimeZone.cc delete mode 100644 include/muduo/base/TimeZone.h delete mode 100644 include/muduo/base/Timestamp.cc delete mode 100644 include/muduo/base/Timestamp.h delete mode 100644 include/muduo/base/Types.h delete mode 100644 include/muduo/base/WeakCallback.h delete mode 100644 include/muduo/base/copyable.h delete mode 100644 include/muduo/base/noncopyable.h delete mode 100644 include/muduo/base/tests/AsyncLogging_test.cc delete mode 100644 include/muduo/base/tests/Atomic_unittest.cc delete mode 100644 include/muduo/base/tests/BlockingQueue_bench.cc delete mode 100644 include/muduo/base/tests/BlockingQueue_test.cc delete mode 100644 include/muduo/base/tests/BoundedBlockingQueue_test.cc delete mode 100644 include/muduo/base/tests/CMakeLists.txt delete mode 100644 include/muduo/base/tests/Date_unittest.cc delete mode 100644 include/muduo/base/tests/Exception_test.cc delete mode 100644 include/muduo/base/tests/FileUtil_test.cc delete mode 100644 include/muduo/base/tests/Fork_test.cc delete mode 100644 include/muduo/base/tests/GzipFile_test.cc delete mode 100644 include/muduo/base/tests/LogFile_test.cc delete mode 100644 include/muduo/base/tests/LogStream_bench.cc delete mode 100644 include/muduo/base/tests/LogStream_test.cc delete mode 100644 include/muduo/base/tests/Logging_test.cc delete mode 100644 include/muduo/base/tests/Mutex_test.cc delete mode 100644 include/muduo/base/tests/ProcessInfo_test.cc delete mode 100644 include/muduo/base/tests/SingletonThreadLocal_test.cc delete mode 100644 include/muduo/base/tests/Singleton_test.cc delete mode 100644 include/muduo/base/tests/ThreadLocalSingleton_test.cc delete mode 100644 include/muduo/base/tests/ThreadLocal_test.cc delete mode 100644 include/muduo/base/tests/ThreadPool_test.cc delete mode 100644 include/muduo/base/tests/Thread_bench.cc delete mode 100644 include/muduo/base/tests/Thread_test.cc delete mode 100644 include/muduo/base/tests/TimeZone_unittest.cc delete mode 100644 include/muduo/base/tests/Timestamp_unittest.cc delete mode 100644 include/muduo/net/Acceptor.cc delete mode 100644 include/muduo/net/Acceptor.h delete mode 100644 include/muduo/net/BUILD.bazel delete mode 100644 include/muduo/net/Buffer.cc delete mode 100644 include/muduo/net/Buffer.h delete mode 100644 include/muduo/net/CMakeLists.txt delete mode 100644 include/muduo/net/Callbacks.h delete mode 100644 include/muduo/net/Channel.cc delete mode 100644 include/muduo/net/Channel.h delete mode 100644 include/muduo/net/Connector.cc delete mode 100644 include/muduo/net/Connector.h delete mode 100644 include/muduo/net/Endian.h delete mode 100644 include/muduo/net/EventLoop.cc delete mode 100644 include/muduo/net/EventLoop.h delete mode 100644 include/muduo/net/EventLoopThread.cc delete mode 100644 include/muduo/net/EventLoopThread.h delete mode 100644 include/muduo/net/EventLoopThreadPool.cc delete mode 100644 include/muduo/net/EventLoopThreadPool.h delete mode 100644 include/muduo/net/InetAddress.cc delete mode 100644 include/muduo/net/InetAddress.h delete mode 100644 include/muduo/net/Poller.cc delete mode 100644 include/muduo/net/Poller.h delete mode 100644 include/muduo/net/Socket.cc delete mode 100644 include/muduo/net/Socket.h delete mode 100644 include/muduo/net/SocketsOps.cc delete mode 100644 include/muduo/net/SocketsOps.h delete mode 100644 include/muduo/net/TcpClient.cc delete mode 100644 include/muduo/net/TcpClient.h delete mode 100644 include/muduo/net/TcpConnection.cc delete mode 100644 include/muduo/net/TcpConnection.h delete mode 100644 include/muduo/net/TcpServer.cc delete mode 100644 include/muduo/net/TcpServer.h delete mode 100644 include/muduo/net/Timer.cc delete mode 100644 include/muduo/net/Timer.h delete mode 100644 include/muduo/net/TimerId.h delete mode 100644 include/muduo/net/TimerQueue.cc delete mode 100644 include/muduo/net/TimerQueue.h delete mode 100644 include/muduo/net/ZlibStream.h delete mode 100644 include/muduo/net/boilerplate.cc delete mode 100644 include/muduo/net/boilerplate.h delete mode 100644 include/muduo/net/http/BUILD.bazel delete mode 100644 include/muduo/net/http/CMakeLists.txt delete mode 100644 include/muduo/net/http/HttpContext.cc delete mode 100644 include/muduo/net/http/HttpContext.h delete mode 100644 include/muduo/net/http/HttpRequest.h delete mode 100644 include/muduo/net/http/HttpResponse.cc delete mode 100644 include/muduo/net/http/HttpResponse.h delete mode 100644 include/muduo/net/http/HttpServer.cc delete mode 100644 include/muduo/net/http/HttpServer.h delete mode 100644 include/muduo/net/http/tests/HttpRequest_unittest.cc delete mode 100644 include/muduo/net/http/tests/HttpServer_test.cc delete mode 100644 include/muduo/net/inspect/BUILD.bazel delete mode 100644 include/muduo/net/inspect/CMakeLists.txt delete mode 100644 include/muduo/net/inspect/Inspector.cc delete mode 100644 include/muduo/net/inspect/Inspector.h delete mode 100644 include/muduo/net/inspect/PerformanceInspector.cc delete mode 100644 include/muduo/net/inspect/PerformanceInspector.h delete mode 100644 include/muduo/net/inspect/ProcessInspector.cc delete mode 100644 include/muduo/net/inspect/ProcessInspector.h delete mode 100644 include/muduo/net/inspect/SystemInspector.cc delete mode 100644 include/muduo/net/inspect/SystemInspector.h delete mode 100644 include/muduo/net/inspect/tests/BUILD.bazel delete mode 100644 include/muduo/net/inspect/tests/Inspector_test.cc delete mode 100644 include/muduo/net/poller/DefaultPoller.cc delete mode 100644 include/muduo/net/poller/EPollPoller.cc delete mode 100644 include/muduo/net/poller/EPollPoller.h delete mode 100644 include/muduo/net/poller/PollPoller.cc delete mode 100644 include/muduo/net/poller/PollPoller.h delete mode 100644 include/muduo/net/protobuf/BufferStream.h delete mode 100644 include/muduo/net/protobuf/CMakeLists.txt delete mode 100644 include/muduo/net/protobuf/ProtobufCodecLite.cc delete mode 100644 include/muduo/net/protobuf/ProtobufCodecLite.h delete mode 100644 include/muduo/net/protorpc/CMakeLists.txt delete mode 100644 include/muduo/net/protorpc/README delete mode 100644 include/muduo/net/protorpc/RpcChannel.cc delete mode 100644 include/muduo/net/protorpc/RpcChannel.h delete mode 100644 include/muduo/net/protorpc/RpcCodec.cc delete mode 100644 include/muduo/net/protorpc/RpcCodec.h delete mode 100644 include/muduo/net/protorpc/RpcCodec_test.cc delete mode 100644 include/muduo/net/protorpc/RpcServer.cc delete mode 100644 include/muduo/net/protorpc/RpcServer.h delete mode 100644 include/muduo/net/protorpc/google-inl.h delete mode 100644 include/muduo/net/protorpc/rpc.proto delete mode 100644 include/muduo/net/protorpc/rpcservice.proto delete mode 100644 include/muduo/net/tests/Buffer_unittest.cc delete mode 100644 include/muduo/net/tests/CMakeLists.txt delete mode 100644 include/muduo/net/tests/Channel_test.cc delete mode 100644 include/muduo/net/tests/EchoClient_unittest.cc delete mode 100644 include/muduo/net/tests/EchoServer_unittest.cc delete mode 100644 include/muduo/net/tests/EventLoopThreadPool_unittest.cc delete mode 100644 include/muduo/net/tests/EventLoopThread_unittest.cc delete mode 100644 include/muduo/net/tests/EventLoop_unittest.cc delete mode 100644 include/muduo/net/tests/InetAddress_unittest.cc delete mode 100644 include/muduo/net/tests/TcpClient_reg1.cc delete mode 100644 include/muduo/net/tests/TcpClient_reg2.cc delete mode 100644 include/muduo/net/tests/TcpClient_reg3.cc delete mode 100644 include/muduo/net/tests/TimerQueue_unittest.cc delete mode 100644 include/muduo/net/tests/ZlibStream_unittest.cc create mode 100644 step.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 50238fd..5445c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ if(NOT TARGET nanodbc) endif() #find- rapidjson -find_package(RapidJson REQUIRED) +find_package(RapidJSON REQUIRED) #already put muduo in the project diff --git a/Src/Center/Center.cpp b/Src/Center/Center.cpp index f147e37..1346f24 100644 --- a/Src/Center/Center.cpp +++ b/Src/Center/Center.cpp @@ -31,7 +31,7 @@ void center::read_config() static std::string config_file_path {"CenterConfig.txt"}; static std::ifstream in {config_file_path, std::ios::in}; Setting set {}; memset(&set, 0, sizeof(Setting)); - uint next_read_interval {0}; + uint next_read_interval {15}; auto read_data = [&]() { if(!in.is_open()) @@ -43,19 +43,19 @@ void center::read_config() if(line.size() < 2 || line.front() == '/') continue; else if(line.find("next_read") != std::string::npos) - next_read_interval = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + next_read_interval = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); else if(line.find("load_record") != std::string::npos) - set.mir_load_record_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + set.mir_load_record_interval_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); else if(line.find("load_dblog") != std::string::npos) - set.mir_dblog_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + set.mir_dblog_interval_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); else if(line.find("max_disbeat") != std::string::npos) - set.mir_max_disbeat_time_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + set.mir_max_disbeat_time_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); else if(line.find("login_cache") != std::string::npos) - set.cli_login_cache_time_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + set.cli_login_cache_time_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); else if(line.find("balance") != std::string::npos) - set.load_balance_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + set.load_balance_interval_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); else if(line.find("clear_mirs") != std::string::npos) - set.clear_mirs_data_time_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); + set.clear_mirs_data_time_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); } }; @@ -76,8 +76,15 @@ void center::read_config() //交换主副配置指针 swap(telemeter::setting_copy, telemeter::setting); //atomic operation + LOG_INFO << "read config, interval: " << next_read_interval << "s, current setting:"; + LOG_INFO << "load record interval: " << telemeter::setting->mir_load_record_interval_; + LOG_INFO << "load database interval: " << telemeter::setting->mir_dblog_interval_; + LOG_INFO << "load balance interval: " << telemeter::setting->load_balance_interval_; + LOG_INFO << "max disbeat interval: " << telemeter::setting->mir_max_disbeat_time_; + LOG_INFO << "clear mirs data time: " << telemeter::setting->clear_mirs_data_time_; + LOG_INFO << "login cache time: " << telemeter::setting->cli_login_cache_time_; //挂起该进程 - sleep(next_read_interval * 1000); + sleep(next_read_interval); } } @@ -92,6 +99,7 @@ void center::wait_cli_login() //纠正树形结构中cli信息的任务, 将交给线程池异步执行 auto correct_tree_structure = [&](uuid cli_id){ + LOG_INFO << "correct info in tree-like structure of client id: " << cli_id; for(auto& kvp : mirs_data_) { if(kvp.second.contains(cli_id)) @@ -144,6 +152,8 @@ void center::wait_cli_login() //按照协议格式进行解析, 并且得到ip等其他信息 memcpy(uidbuf.data(), packet.data(), protocal::kCLI_LOGIN_UID_); + for(auto& ch :uidbuf) + ch += '0'; size_t uid = std::atol(uidbuf.data()); memcpy(statebuf.data(), packet.data() + protocal::kCLI_LOGIN_UID_, protocal::kCLI_LOGIN_STATE_); size_t state = statebuf[0]; @@ -190,12 +200,17 @@ void center::wait_cli_login() //cookie为空或者没有找到时, 记录cli登录信息 if(cached == false) { + if(this->mirs_data_.size() == 0) + memset(&available_mir, 0, sizeof(IP)); + else if(this->mirs_data_.size() == 1) + available_mir = (*mirs_data_.begin()).first; //回复可用mir地址 int send_num = sendto(sock_fd, &available_mir, sizeof(available_mir), 0, (sockaddr*)&addr_cli, sizeof(addr_cli)); login_count++; //数据库记录日志 //dblog(cli_login, uid); + LOG_INFO << "client login, uid: " << uid << ", reply mirs ip: " << available_mir.to_string(); if(this->all_cli_.count(uid) == 0) this->all_cli_.insert(uid); else @@ -220,8 +235,10 @@ void center::wait_cli_login() if(atom_mutex_ == false) { atom_mutex_ = true; + uuid id = cookie_.front(); cookie_.pop_front(); atom_mutex_ = false; + LOG_INFO << "erase login cache of client: " << id; } else continue; @@ -231,6 +248,7 @@ void center::wait_cli_login() } else //锁被pop队头或者查询任务使用中 { + LOG_INFO << "cached client login, no reply for client : " << uid; continue; } } @@ -314,6 +332,7 @@ void center::listen_mir_beat() int i = 3; //占位避免编译器报warning //dblog(MIR_DISCONECT); mirs_data_.erase(kvp.first); + LOG_INFO << "mirror disconnect: " << const_cast(&kvp.first)->to_string(); } } } @@ -324,16 +343,28 @@ void center::listen_mir_beat() void center::clear_mirs_data() { - //while(true) + auto get_next_zeropoint = [](){ + time_t t = time(NULL); + struct tm * tm= localtime(&t); + tm->tm_mday += 1; + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + return mktime(tm); + }; + + while(true) { - //sleep(nowtime - nextzeropoint + setting->clear_mirsdata_time); - //mirs_data_.clear(); - //all_cli_.clear(); + sleep(get_next_zeropoint() - time(NULL) + telemeter::setting->clear_mirs_data_time_); + mirs_data_.clear(); + all_cli_.clear(); + LOG_INFO << "clear mirrors data successfully"; } } IP center::load_balance() { + LOG_INFO << "load balance occurs"; //暂时不优化 for(auto& kvp : mirs_data_) { @@ -379,7 +410,7 @@ void center::log_info(std::exception& e, const char* crush_file) log << "Mirrors & dispatched client:\n"; for(auto& kvp : mirs_data_) { - log << "ip: " << kvp.first + log << "ip: " << const_cast(&kvp.first)->to_string() << " load state: " << tostring(kvp.second.get_load_level()) << '\n'; log << "dispatched client: \n"; for(auto uid : kvp.second.get_dispatched_cli()) @@ -398,8 +429,3 @@ void center::log_info(std::exception& e, const char* crush_file) } } } - - - - - diff --git a/Src/Common/ServerBase.cpp b/Src/Common/ServerBase.cpp index 0369085..ee821af 100644 --- a/Src/Common/ServerBase.cpp +++ b/Src/Common/ServerBase.cpp @@ -49,6 +49,10 @@ scu_time scu_time::toScutime(const muduo::Timestamp ×tamp){ int seconds = allSeconds % 86400; size_t hour = seconds / 3600; size_t minute = (seconds - hour * 3600) / 60; + if(hour >= 16) + hour -= 16; + else + hour += 8; return scu_time(hour, minute); } diff --git a/Src/Mirror/Mirror.cpp b/Src/Mirror/Mirror.cpp index 27ff94c..3a57dac 100644 --- a/Src/Mirror/Mirror.cpp +++ b/Src/Mirror/Mirror.cpp @@ -5,13 +5,113 @@ using std::placeholders::_1; using std::placeholders::_2; using std::placeholders::_3; +void Mirror::init() { + + + auto judge_lesson_order = [this](const std::vector &time_table) -> size_t { + scu_time now{scu_time::toScutime(muduo::Timestamp::now())}; + if (now < time_table[0]) + return 0; + for (size_t i = 1; i < time_table.size(); i++) { + if (now < time_table[i]) + return i; + } + return 12; + }; + + //读取配置文件 + static std::string config_file_path = this->config_file_path; + + static std::ifstream in{config_file_path, std::ios::in}; + + if (!in.is_open()) + in.open(config_file_path, std::ios::in); + + std::string line{}; + + while (in.good()) { + std::getline(in, line, '\n'); + if (line.size() < 2 || line.front() == '/') + continue; + else if (line.find("mir_heart") != std::string::npos) + telemeter::setting->mir_heart_beat_interval = std::stoi( + std::string(line.begin() + line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("mir_load") != std::string::npos) + telemeter::setting->mir_load_report_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("img_path") != std::string::npos) + telemeter::setting->img_path = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_source") != std::string::npos) + telemeter::setting->db_source = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_user") != std::string::npos) + telemeter::setting->db_user = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_password") != std::string::npos) + telemeter::setting->db_password = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("center_ip") != std::string::npos) + telemeter::setting->center_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("update_pic_interval") != std::string::npos) + telemeter::setting->update_pic_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("utc_time") != std::string::npos) + telemeter::setting->utc_time = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("update_calendar_time") != std::string::npos) + telemeter::setting->update_calendar_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("clear_clients_time") != std::string::npos) + telemeter::setting->clear_clients_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("course_interval") != std::string::npos) + telemeter::setting->course_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + } + //初始化数据库 + this->conn = nanodbc::connection(telemeter::setting->db_source,telemeter::setting->db_user,telemeter::setting->db_password); + + //更新section + this->wj_section = judge_lesson_order(this->wj_Time); + this->ja_section = judge_lesson_order(this->ja_Time); + + //更新日期 + muduo::Timestamp now(muduo::Timestamp::now()); + std::string formattedTime = now.toFormattedString(false); + //获取年 + int year = std::stoi(formattedTime.substr(0, 4)); + //获取月 + int month = std::stoi(formattedTime.substr(4, 2)); + //获取日 + int date = std::stoi(formattedTime.substr(6, 2)); + //更新数据 + scu_date scudate = db_control::update_calendar(this->conn, year, month, date); + //更新至原子量 + this->day = scudate.day; + this->week = scudate.week; + + //下载图片缓存 + + + + std::vector backgrounds; + db_control::query_background(conn, backgrounds); + //数据 + + //循环 + for (auto iter = backgrounds.begin(); iter != backgrounds.end(); iter++) { + //解码 + 储存图片 + //路径 + std::string path = telemeter::setting->img_path + "/" + std::to_string(iter->PicId) + ".jpg"; + + + codec::downPic(path, iter->PicCode); + } + + +}; + void Mirror::start() { //初始化配置文件及各数据 this->init(); + LOG_INFO << "init success"; //任务队列最大数量 - pool_.setMaxQueueSize(30); //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 pool_.start(static_cast(2 * std::thread::hardware_concurrency())); @@ -19,9 +119,6 @@ void Mirror::start() { std::clog << "thread start: " << info << std::endl; }; - // db_config 初始化 - nanodbc::connection conn = nanodbc::connection(db_dsn, db_name, db_passwd); - //发送负载情况(Task2) this->pool_.run([this]() { update_data_info(); }); thd_start("update data info"); @@ -34,13 +131,22 @@ void Mirror::start() { this->pool_.run([this]() { read_config(); }); thd_start("read config"); - //清空(Task5) + this->pool_.run([this]() { clear_cli_data(); }); thd_start("clear cli data"); + this->pool_.run([this]() { update_course_section(); }); + thd_start("update_course_section"); + + this->pool_.run([this]() { update_school_calendar(); }); + thd_start("update school calendar"); + + this->pool_.run([this]() { update_pictures_info(); }); + thd_start("update_pictures_info"); + //TCP相关(Task6) this->listen_cli_beat(); - thd_start("listen client beat") + thd_start("listen client beat"); //输出日志 } @@ -52,7 +158,7 @@ void Mirror::update_data_info() { // 更新间隔 size_t time = 0; - unsigned char this_ip[4] = "0000";//解析ip + unsigned char this_ip[4] = {'0', '0', '0', '0'};//解析ip // 发送的息 char send_buf[8] = {0}; @@ -78,8 +184,8 @@ void Mirror::update_data_info() { // getMyip std::string host; std::string ip; - bool ret = GetHostInfo(host, ip); - if (!ret) { + bool err = GetHostInfo(host, ip); + if (!err) { //报错 } IP this_ip(ip); @@ -96,7 +202,7 @@ void Mirror::update_data_info() { // DtlLoadState.net_load_ = netLoad; //this_ip - std::vector ret{}; + std::vector ret; ret.push_back(this_ip.seg0); ret.push_back(this_ip.seg1); ret.push_back(this_ip.seg2); @@ -128,7 +234,7 @@ void Mirror::update_data_info() { //线程主循环 while (true) { - if (time == telemeter::setting->mir_load_report_interval_) { + if (time == telemeter::setting->mir_load_report_interval) { //to_string(8byte) = 4+1+1+1+1 true/false //重置缓冲 memset(send_buf, 0, sizeof(send_buf)); @@ -145,6 +251,8 @@ void Mirror::update_data_info() { //重置time time = 1; + + LOG_INFO << "update pack"; } // 发送‘心跳包’ @@ -158,18 +266,309 @@ void Mirror::update_data_info() { servaddr.sin_port = htons(port::kMIR_BEAT_); // 设置发送ip /*修改:若发送失败,则沿用之前的ip*/ - servaddr.sin_addr.s_addr = inet_addr(setting->center_ip_); + servaddr.sin_addr.s_addr = inet_addr((telemeter::setting->center_ip).c_str()); // 发送缓存 sendto(sock, send_buf, strlen(send_buf), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); // 统计发送心跳包次数 time++; //心跳包频率 - sleep(telemeter::setting->mir_heart_beat_interval_ * 1000); + sleep(telemeter::setting->mir_heart_beat_interval); } } +//定时拉取数据库信息, 更新时间戳 + +//读取配置文件 +void Mirror::read_config() { + + +// 后可以考虑使用json格式 + static std::string config_file_path = this->config_file_path; + static std::ifstream in{config_file_path, std::ios::in}; + Setting set{}; + size_t next_read_interval{0}; + + auto read_data = [&]() { + if (!in.is_open()) + in.open(config_file_path, std::ios::in); + std::string line{}; + while (in.good()) { + std::getline(in, line, '\n'); + if (line.size() < 2 || line.front() == '/') + continue; + else if (line.find("next_read") != std::string::npos) + next_read_interval = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("mir_heart") != std::string::npos) + set.mir_heart_beat_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("mir_load") != std::string::npos) + set.mir_load_report_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("img_path") != std::string::npos) + set.img_path = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_source") != std::string::npos) + set.db_source = std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']')); + else if (line.find("db_user") != std::string::npos) + set.db_user = std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']')); + else if (line.find("db_password") != std::string::npos) + set.db_password = std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']')); + else if (line.find("center_ip") != std::string::npos) + set.center_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("update_pic_interval") != std::string::npos) + set.update_pic_interval = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("utc_time: ") != std::string::npos) + set.utc_time = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("update_calendar_time:") != std::string::npos) + set.update_calendar_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("clear_clients_time:") != std::string::npos) + set.clear_clients_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("course_interval:") != std::string::npos) + set.course_interval = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + + } + }; + + + auto swap = [](Setting *src, Setting *dst) { + Setting *tmp = dst; + dst = src; + src = tmp; + }; + + //主任务 + while (true) { + //读取配置文件 + read_data(); + + //复制到配置副本中 + *telemeter::setting_copy = set; + + //交换主副配置指针 + swap(telemeter::setting_copy, telemeter::setting); //atomic operation + + //挂起该进程 + sleep(next_read_interval); + } +} + +//清除mirror->client树信息 +void Mirror::clear_cli_data() { + + auto get_seconds_from_now = [&](const scu_time &time) { + scu_time nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + + while (true) { + + //加锁 + Class2Campus.clear(); + + cli_info_.clear(); + + //配置文件读取upload,time + std::string clear_time = telemeter::setting->clear_clients_time; + int index = clear_time.find_last_of(":"); + //获取小时 + int hour = std::stoi(clear_time.substr(0, index)); + //获取分钟 + int minute = std::stoi(clear_time.substr(index + 1)); + + sleep(get_seconds_from_now(scu_time(hour, minute))); + //每日24时更新 + } +} + +//定时 更新课程节次信息,包括江安与望江 +//更新course间隔 +void Mirror::update_course_section() { + + auto judge_lesson_order = [this](const std::vector &time_table) -> size_t { + scu_time now{scu_time::toScutime(muduo::Timestamp::now())}; + if (now < time_table[0]) + return 0; + for (size_t i = 1; i < time_table.size(); i++) { + if (now < time_table[i]) + return i; + } + return 12; + }; + + + while (true) { + wj_section = judge_lesson_order(this->wj_Time); + ja_section = judge_lesson_order(this->ja_Time); + + sleep(telemeter::setting->course_interval); + } +} + +//定时 更新校历信息 +void Mirror::update_school_calendar() { + auto get_seconds_from_now = [&](const scu_time &time) { + scu_time nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + while (true) { + //获取当前时间 + muduo::Timestamp now(muduo::Timestamp::now()); + std::string formattedTime = now.toFormattedString(false); + //获取年 + int year = std::stoi(formattedTime.substr(0, 4)); + //获取月 + int month = std::stoi(formattedTime.substr(4, 2)); + //获取日 + int date = std::stoi(formattedTime.substr(6, 2)); + //更新数据 + scu_date scudate = db_control::update_calendar(this->conn, year, month, date); + //更新至原子量 + day = scudate.day; + week = scudate.week; + //配置文件读取upload,time + + std::string update_time = telemeter::setting->update_calendar_time; + int index = update_time.find_last_of(":"); + //获取小时 + int hour = std::stoi(update_time.substr(0, index)); + //获取分钟 + int minute = std::stoi(update_time.substr(index + 1)); + + sleep(get_seconds_from_now(scu_time(hour, minute))); + //每日24时更新 + } +} + +//待修改配置文件 +void Mirror::update_pictures_info() { + + scu_time nowtime = scu_time::toScutime(muduo::Timestamp::now()); + //从6/12/18点开始更新 + if (nowtime < scu_time(6, 0)) + sleep((scu_time(6, 0) - nowtime).toSeconds()); + else if (nowtime < scu_time(12, 0)) + sleep((scu_time(12, 0) - nowtime).toSeconds()); + else if (nowtime < scu_time(18, 0)) + sleep((scu_time(18, 0) - nowtime).toSeconds()); + else + sleep((scu_time(24, 0) - nowtime).toSeconds()); + + while (true) { + //查询数据库 + + std::vector backgrounds; + + db_control::query_background(conn, backgrounds); + //图片信息与 + //数据 + //循环 + for (auto iter = backgrounds.begin(); iter != backgrounds.end(); iter++) { + //解码 + 储存图片 + //路径 + std::string path = telemeter::setting->img_path + "/" + std::to_string(iter->PicId) + ".jpg"; + + codec::downPic(path, iter->PicCode); + } + + sleep(telemeter::setting->update_pic_interval * 60 * 60); + } + +} + +//多并发 +void Mirror::listen_cli_beat() { + muduo::net::EventLoop loop_; + muduo::net::TcpServer server_(&loop_, muduo::net::InetAddress(port::kCLI_BEAT_), ""); + //set server.onConnect 连接函数 + server_.setMessageCallback(std::bind(&Mirror::on_message, this, _1, _2, _3)); + server_.start(); + loop_.loop(); +} + +//更新参数, 如Scu_date与scu_time->skjc + + +//待修改配置时间 +void Mirror::on_message(const muduo::net::TcpConnectionPtr &connectionPtr, + muduo::net::Buffer *msg, + muduo::Timestamp time) { + std::string src = msg->retrieveAllAsString(); + Cli::Uuid id; + std::string timeStamp; + json_control::getIdAndStamp(src, id, timeStamp); + OldHash old; + //查找到旧数据的哈希值 + if (this->cli_info_.find(id) != this->cli_info_.end()) { + old = this->cli_info_[id]; + } else { + std::deque msgs; + msgs.push_back(0); + OldHash temp_hush; + temp_hush.url_ = 0; + temp_hush.event_ = 0; + temp_hush.next_event_ = 0; + temp_hush.msgs_ = msgs; + this->cli_info_.insert(std::pair(id, temp_hush)); + old = this->cli_info_[id]; + } + + //去数据库中查询新数据 + std::string now_stamp = muduo::Timestamp::now().toString(); + //分析当前的时间戳 + unsigned long stamp = std::stoul(now_stamp); + stamp -= telemeter::setting->utc_time * 60 * 60;//(UTC+8h) //误差时间 + + int course_section; + if (Class2Campus.find(id) == Class2Campus.end()) { + CliDes new_des; + new_des.id = id; + new_des.campus = db_control::find_campus(this->conn, id); + new_des.stamp = now_stamp; + Class2Campus.insert(std::pair(id, new_des)); + } + + if (Class2Campus[id].campus == 3) { //江安校区 + course_section = this->ja_section; + } else { + course_section = this->wj_section; + } + + bool next_event = true; + if (course_section == 4 || course_section == 9 || course_section == 12) + next_event = false; + + + std::string pic_url = telemeter::setting->img_path + "/" + db_control::find_pic(this->conn, id) + ".jpg"; + + std::deque msgs = db_control::find_mes(this->conn, id, std::to_string(stamp)); //统一utc时间 + + Lesson lesson_1 = db_control::find_lesson(this->conn, id, course_section, scu_date(this->week, this->day)); + Lesson lesson_2; + if (next_event) { + lesson_2 = db_control::find_lesson(this->conn, id, course_section + 1, scu_date(this->week, this->day)); + } + OldHash new_hash; + new_hash.url_ = std::hash()(pic_url); + new_hash.event_ = std::hash()(lesson_1); + new_hash.next_event_ = std::hash()(lesson_2); + std::deque msgs_hash; + for (auto iter = msgs.begin(); iter != msgs.end(); iter++) { + msgs_hash.push_back(std::hash()(*iter)); + } + + if (new_hash == old) + connectionPtr->send(json_control::no_need_update); + else { + ClassMes sendInfo; + sendInfo.image_url = pic_url; + sendInfo.messages = msgs; + sendInfo.lesson_1 = lesson_1; + sendInfo.lesson_2 = lesson_2; + std::string info = json_control::getJsonInfo(sendInfo, now_stamp); + connectionPtr->send(info); + } + +} -//定时拉取数据库信息, 更新时间戳 //暂停该函数 /* void Mirror::update_clis_data() { @@ -328,7 +727,7 @@ void Mirror::update_clis_data() { // 进入任务线程阶段 while (true) { // 挂起. 7.55唤醒 - sleep(get_seconds_from_now(scu_time(7, 55)) * 1000); + sleep(get_seconds_from_now(scu_time(7, 55))); while (true) { nowTime = scu_time::toScutime(muduo::Timestamp::now());//记录当前时间 @@ -338,9 +737,9 @@ void Mirror::update_clis_data() { if (sleepSeconds == 0) break; //休眠至下一次更新 - sleep(sleepSeconds * 1000); + sleep(sleepSeconds); } - sleep(get_seconds_from_now(scu_time(24, 0)) * 1000); //沉睡至24点 + sleep(get_seconds_from_now(scu_time(24, 0)) ); //沉睡至24点 // 24点更新当日上课信息 update_scu_date(); } @@ -349,202 +748,8 @@ void Mirror::update_clis_data() { } */ -//读取配置文件 -/*待更改*/ -void Mirror::read_config() { - -// 后可以考虑使用json格式 - static std::string config_file_path{"MirrorConfig.txt"}; - static std::ifstream in{config_file_path, std::ios::in}; - Setting set{}; - memset(&set, 0, sizeof(Setting)); - size_t next_read_interval{0}; - - auto read_data = [&]() { - if (!in.is_open()) - in.open(config_file_path, std::ios::in); - std::string line{}; - while (in.good()) { - std::getline(in, line, '\n'); - if (line.size() < 2 || line.front() == '/') - continue; - else if (line.find("next_read") != std::string::npos) - next_read_interval = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - else if (line.find("mir_heart") != std::string::npos) - set.mir_heart_beat_interval_ = std::stoi( - std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - else if (line.find("mir_load") != std::string::npos) - set.mir_load_report_interval_ = std::stoi( - std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - else if (line.find("cli_class") != std::string::npos) - set.cli_class_info_cache_time_ = std::stoi( - std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - } - }; - - - auto swap = [](Setting *src, Setting *dst) { - Setting *tmp = dst; - dst = src; - src = tmp; - }; - - //主任务 - while (true) { - //读取配置文件 - read_data(); - - //复制到配置副本中 - memcpy(telemeter::setting_copy, &set, sizeof(Setting)); - - //交换主副配置指针 - swap(telemeter::setting_copy, telemeter::setting); //atomic operation - - //挂起该进程 - sleep(next_read_interval * 1000); - } -} - -//清除mirror->client树信息 -void Mirror::clear_cli_data() { - auto update_uC_map = [](const std::unordered_map &data_map, - std::unordered_map *origin_map, - std::unordered_map *copy_map) { - //赋值 - *copy_map = data_map; -// 交换指针 - auto tmp = copy_map; - copy_map = origin_map; - origin_map = tmp; - }; - auto get_seconds_from_now = [&](const scu_time &time) { - nowTime = scu_time::toScutime(muduo::Timestamp::now()); - return time <= nowTime ? 0 : (time - nowTime).toSeconds(); - }; - while (true) { - std::unordered_map newmap; - update_uC_map(newmap, wj_clis_data, wj_clis_data_copy); - update_uC_map(newmap, ja_clis_data, ja_clis_data_copy); - - //配置文件读取upload,time - sleep(get_seconds_from_now(scu_time(24, 0)) * 1000); - //每日24时更新 - } -} - -void Mirror::update_pictures_info() { - //while true - auto swap = []() { - - }; - - while (true) { - //查询数据库 - - std::vector backgrounds; - - db_control::query_background(conn, backgrounds); - //图片信息与 - //数据 - //循环 - for (auto iter = backgorunds->begin(); iter != backgorunds->end(); iter++) { - //解码 + 储存图片 - //路径 - std::string path = this.img_path + "/" + std::to_string(iter->PicId) + ".jpg"; - - codec::downPic(path, iter->PicCode); - } - - sleep(setting->update_pic_interval * 60 * 60 * 1000) - } - -} - -//多并发 -void Mirror::listen_cli_beat() { - muduo::net::EventLoop loop_; - muduo::net::TcpServer server_(&loop_, muduo::net::InetAddress(port::kCLI_BEAT_), ""); - //set server.onConnect 连接函数 - server_.setMessageCallback(&Mirror::on_message); - server_.start(); - loop_.loop(); -} - -//更新参数, 如Scu_date与scu_time->skjc - - -//待修改 -void Mirror::on_message(const muduo::net::TcpConnectionPtr &connectionPtr, - muduo::net::Buffer *msg, - muduo::Timestamp time) { - std::string src = msg->retrieveAsString(); - Cli::Uuid id; - std::string timeStamp; - getIdAndStamp(src, id, timeStamp); - - //查找到旧数据的哈希值 - if (this->cli_info_.find(id) != this->cli_info_.end()) { - OldHash old = this->cli_info_[id]; - } else { - OldHash temp_hush{0, 0, 0, 0}; - this->cli_info_.insert(std::pair(id, temp_hush)); - } - - //去数据库中查询新数据 - std::string now_stamp = muduo::Timestamp::now().toString(); - //分析当前的时间戳 - unsigned long stamp = std::stoul(now_stamp); - stamp -= 8 * 60 * 60;//(UTC+8h) - - int course_section; - if (Class2Campus.find(id) == Class2Campus.end()) { - CliDes new_des; - new_des.id = id; - new_des.campus = find_campus; - new_des.stamp = now_stamp; - Class2Campus.insert(std::pair(id, new_des)); - } - - if (Class2Campus[id].campus == 3) { //江安校区 - course_section = this->ja_section; - } else { - couse_section = this->wj_section; - } - - bool next_event = true; - if (course_section == 4 || course_section == 9 || course_section == 12) - next_event = false; - - std::string pic_url = db_control::find_pic(this->conn, id, now_stamp); - std::deque msg = db_control::find_mes(this->conn, id, std::to_string(stamp)); //统一utc时间 - Lesson lesson_1 = db_control::find_lesson(this->conn, id, course_section, this->week, this->day); - Lesson lesson_2; - if (next_event) { - lesson_2 = db_control::find_lesson(this->conn, id, course_section + 1, this->week, this->day); - } - OldHash new_hash{ - std::hash()(pic_url), - std::hash < std::deque < std::string >> ()(msg), - std::hash()(lesson_1), - //这里next_event暂时不知道从哪个数据中哈希, 置为0 - std::hash()(lesson_2) - }; - - if (new_hash == old) - conn->send(json_control::no_need_update); - else { - ClassMes sendInfo; - sendInfo.img_url = pic_url; - sendInfo.messages = msg; - sendInfo.lesson_1 = lesson_1; - sendInfo.lesson_2 = lesson_2; - std::string info = json_lib::getJsonInfo(sendInfo, now_stamp); - conn->send(info); - } - -} - +/* void Mirror::update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, muduo::Timestamp *copy_campus_stamp) { @@ -559,3 +764,4 @@ void Mirror::update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestam }; swap(origin_campus_stamp, copy_campus_stamp); } +*/ \ No newline at end of file diff --git a/Src/Mirror/MirrorMain.cpp b/Src/Mirror/MirrorMain.cpp index af3b86c..fd29af6 100644 --- a/Src/Mirror/MirrorMain.cpp +++ b/Src/Mirror/MirrorMain.cpp @@ -1,6 +1,6 @@ #include -#include "Mirror.cpp" +#include int main() { @@ -11,8 +11,8 @@ int main() { mir.start(); } - catch(std::exception& e) + catch(const std::exception& e) { - std::cerr << e.what() << '\n'; + LOG_WARN << "some error happens " << e.what() << '\n'; } } diff --git a/Src/Mirror/codec_lib.cpp b/Src/Mirror/codec_lib.cpp index dfe0dc0..2eb9524 100644 --- a/Src/Mirror/codec_lib.cpp +++ b/Src/Mirror/codec_lib.cpp @@ -5,12 +5,12 @@ namespace codec { using base64 = cppcodec::base64_rfc4648; - void downPic(const std::string &code, const std::string &path) { + void downPic( const std::string &path,const std::string &code) { //打开文件 std::ofstream ofs(path, std::ios::trunc | std::ios::binary); //异常处理 if (!ofs) { - exit(-1); + ofs.open(path, std::ios::trunc | std::ios::binary); } //解码 std::vector buff = base64::decode(code); diff --git a/Src/Mirror/db_lib.cpp b/Src/Mirror/db_lib.cpp index 4fd9602..7808ef6 100644 --- a/Src/Mirror/db_lib.cpp +++ b/Src/Mirror/db_lib.cpp @@ -5,6 +5,7 @@ namespace db_control { using Cli::Uuid; + /* void check_week_and_day(nanodbc::connection conn, scu_date &date) { if (date.day == 7) { date.week += 1; @@ -13,13 +14,13 @@ namespace db_control { date.day += 1; } } - +*/ /* * param CCmap uuid->ClassMes * param skjc 上课节次 * */ - +/*暂停使用 void query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, scu_date *date, Uuid id) { @@ -108,45 +109,169 @@ namespace db_control { } } - - void query_background(nanodbc::connection conn, std::vector &backgrounds) { +*/ + void query_background(nanodbc::connection &conn, std::vector &backgrounds) { //查询所有 std::string sel_stmt = "SELECT * FROM backgrounds"; //执行语句 nanodbc::result find_row = nanodbc::execute(conn, sel_stmt); - for (; sel_stmt.next();) { - int id = sel_stmt.get(0); - std::string code = sel_stmt.get(1); - std::string des = sel_stmt.get(2); + for (; find_row.next();) { + int id = find_row.get(0); + std::string code = find_row.get(1); + std::string des = find_row.get(2); backgrounds.emplace_back(id, code, des); } + } - std::string find_pic(const nanodbc::connection &conn, Cli::Uuid id) { + std::string find_pic(nanodbc::connection &conn, Cli::Uuid id) { nanodbc::statement statement(conn); nanodbc::prepare(statement, std::string("SELECT background FROM places WHERE UUID = ?")); - statement.bind(0, std::to_string(id)); + statement.bind(0, &id); - nanodbc::result row = nanodbc.execute(statement); + nanodbc::result row = nanodbc::execute(statement); while (row.next()) { return row.get(0); } + return ""; } + std::deque find_mes(nanodbc::connection &conn, Cli::Uuid id, const std::string &stamp) { + //准备结果 + std::deque res; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, + std::string("SELECT title, expiretime, text FROM msg WHERE uuid = ? AND starttime = ? ;")); + + statement.bind(0, &id); + statement.bind(1, stamp.c_str()); - Lesson find_event(const nanodbc::connection &conn, Cli::Uuid id, nanodbc::connection conn, size_t skjc, scu_date *date, Uuid id){ + nanodbc::result row = nanodbc::execute(statement); + + while (row.next()) { + Message mes; + mes.title = row.get(0); + mes.expireTime = row.get(1); + mes.text = row.get(2); + res.push_back(mes); + } + return res; } - std::deque find_message(const nanodbc::connection& conn, Cli::Uuid id, muduo::Timestamp &stamp){ + Lesson find_lesson(nanodbc::connection &conn, Cli::Uuid id, int skjc, const scu_date &date) { + //准备结果 + Lesson ret; + std::string teacher_name; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, + std::string("SELECT\n" + "U.UUID AS uuid,\n" + "P.kch AS kch,\n" + "P.kxh AS kxh,\n" + "K.kcm AS kcm,\n" + "P.jsxm AS jsxm,\n" + "P.jxdd AS jxdd,\n" + "P.jsszxqh AS jsszxqh\n" + "FROM\n" + "places AS U\n" + "INNER JOIN pksj AS P ON U.place = P.jxdd \n" + "INNER JOIN kcb AS K ON P.kch = K.kch\n" + "WHERE U.UUID = ?\n" + "AND \n" + "P.sksj <= ? AND\n" + "P.sksj + P.cxjc > ? AND\n" + "P.skxq = ? AND\n" + "SUBSTR(qsz,?,1)=1")); + + statement.bind(0, &id); + statement.bind(1, &skjc); + statement.bind(2, &date.day); + statement.bind(3, &date.day); + statement.bind(4, &date.week); + + + nanodbc::result row = nanodbc::execute(statement); + + for (int i = 0; row.next(); i++) { + + if (i != 0) { + teacher_name += ","; + } + ret.kch_ = row.get(1); + ret.kxh_ = row.get(2); + ret.kcm_ = row.get(3); + teacher_name += row.get(4); + ret.jxdd_ = row.get(5); + } + ret.jsxm_ = teacher_name; + + return ret; } + int find_campus(nanodbc::connection &conn, Cli::Uuid id) { + + int ret; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, std::string("SELECT \n" + "distinct P.jsszxqh AS campus \n" + "FROM pksj AS P\n" + "INNER JOIN places AS PL ON P.jxdd = PL.place\n" + "WHERE PL.UUID = ?")); + + statement.bind(0, &id); + + nanodbc::result row = nanodbc::execute(statement); + + while (row.next()) { + ret = row.get(0); + } + + return ret; + } + + scu_date update_calendar(nanodbc::connection &conn, int year, int month, int date) { + + int week; + int day; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, std::string("SELECT \n" + "now_week,\n" + "now_day\n" + "FROM\n" + "calendar\n" + "WHERE\n" + "year = ? AND\n" + "month = ? AND\n" + "date = ?")); + + statement.bind(0, &year); + statement.bind(1, &month); + statement.bind(2, &date); + + nanodbc::result row = nanodbc::execute(statement); + + while (row.next()) { + week = row.get(0); + day = row.get(1); + } + + return scu_date(week,day); + } } diff --git a/Src/Mirror/json_lib.cpp b/Src/Mirror/json_lib.cpp index 3305847..d610ce8 100644 --- a/Src/Mirror/json_lib.cpp +++ b/Src/Mirror/json_lib.cpp @@ -51,7 +51,7 @@ namespace json_control { writer.EndObject(); } - std::string getJsonInfo(const ClassMes &mes, const muduo::Timestamp ×tamp) { + std::string getJsonInfo(const ClassMes &mes, const std::string ×tamp) { rapidjson::StringBuffer strBuf; rapidjson::Writer writer(strBuf); //声明strBuf与writer对象 @@ -61,7 +61,7 @@ namespace json_control { //时间戳 writer.Key("time"); - writer.String(timestamp.toString().c_str()); + writer.String(timestamp.c_str()); //图像的url writer.Key("image_url"); diff --git a/include/Common/ServerBase.hpp b/include/Common/ServerBase.hpp index 70e45db..cbfb213 100644 --- a/include/Common/ServerBase.hpp +++ b/include/Common/ServerBase.hpp @@ -10,8 +10,9 @@ #include struct scu_date { - size_t week; - size_t day; + int week; + int day; + scu_date(int w, int d): week(w), day(d) { }; }; class scu_time { diff --git a/include/Common/Telemeter.hpp b/include/Common/Telemeter.hpp index a66c500..e36e52c 100644 --- a/include/Common/Telemeter.hpp +++ b/include/Common/Telemeter.hpp @@ -59,12 +59,18 @@ const constexpr uint _permanent_thread_num_ = 4U; //center的常驻线程数量 //mirror的setting, POD type struct Setting { - std::string center_ip_; //?解析 -// int backup_center_ip_; - int next_read_interval_; - uint8_t mir_heart_beat_interval_; - uint16_t mir_load_report_interval_; - uint16_t cli_class_info_cache_time_; + int mir_heart_beat_interval; + int mir_load_report_interval; + std::string img_path; + std::string db_source; + std::string db_user; + std::string db_password; + std::string center_ip; + int update_pic_interval; + int utc_time; + std::string update_calendar_time; + std::string clear_clients_time; + int course_interval; //数据库ip? }; #endif @@ -77,7 +83,7 @@ namespace telemeter { #ifdef SRC_CENTER_H //双缓冲配置表解决一写多读线程安全问题 - static Setting _set_cache_one = {60, 5, 15, 60, 20, 0}; + static Setting _set_cache_one = {60, 5, 15, 60, 20, 0}; static Setting _set_cache_two = {60, 5, 15, 60, 20, 0}; //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 static Setting* setting = &_set_cache_one; @@ -102,8 +108,8 @@ namespace telemeter { #endif #ifdef SRC_MIRROR_H - static Setting _set_cache_one = {0,600,1,60,600}; - static Setting _set_cache_two = {0,600,1,60,600}; + static Setting _set_cache_one = {1, 60, "home/jol", "Scucids-server","teacher","zhirui208+", "192.168.233.14", 6,8,"24:00","24:00",60}; + static Setting _set_cache_two = {1, 60, "home/jol", "Scucids-server","teacher","zhirui208+", "192.168.233.14", 6,8,"24:00","24:00",60}; //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 static Setting* setting = &_set_cache_one; static Setting* setting_copy = &_set_cache_two; diff --git a/include/Common/Udp.hpp b/include/Common/Udp.hpp index 56dcb0f..c0629a1 100644 --- a/include/Common/Udp.hpp +++ b/include/Common/Udp.hpp @@ -15,9 +15,9 @@ #include #include #include +#include +#include -//暂时以int表示ip, 有需要则封装成类 -using IP = int; namespace port { @@ -64,9 +64,43 @@ struct IP { this->seg2 = res[2]; this->seg3 = res[3]; } + + std::string to_string() + { + return std::to_string(this->seg0) + '.' + std::to_string(this->seg1) + '.' + std::to_string(this->seg2) + '.' + std::to_string(this->seg3); + } + + bool operator==(const IP& ip)const{ + return this->seg0 == ip.seg0 + && this->seg1 == ip.seg1 + && this->seg2 == ip.seg2 + && this->seg3 == ip.seg3; + } + + IP& operator=(const IP& rhs){ + if(this == &rhs) + return *this; + this->seg0 = rhs.seg0; + this->seg1 = rhs.seg1; + this->seg2 = rhs.seg2; + this->seg3 = rhs.seg3; + return *this; + } }; -bool GetHostInfo(std::string& hostName, std::string& Ip) { +namespace std { + template<> + struct hash : public __hash_base + { + size_t operator()(const IP &ip) const noexcept //这个const noexpect一定要写上去 + { + return (((size_t)ip.seg0) << 24) + (((size_t)ip.seg1) << 16) + (((size_t)ip.seg2) << 8) + ((size_t)ip.seg3) ; + } + }; +} + + +static bool GetHostInfo(std::string& hostName, std::string& Ip) { char name[256]; gethostname(name, sizeof(name)); hostName = name; @@ -75,7 +109,7 @@ bool GetHostInfo(std::string& hostName, std::string& Ip) { char ipStr[32]; const char* ret = inet_ntop(host->h_addrtype, host->h_addr_list[0], ipStr, sizeof(ipStr)); if (NULL==ret) { - std::cout << "hostname transform to ip failed"; +// std::cout << "hostname transform to ip failed"; return false; } Ip = ipStr; diff --git a/include/ServerBase.cpp b/include/ServerBase.cpp deleted file mode 100644 index 5d2f2ea..0000000 --- a/include/ServerBase.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -bool scu_time::operator=(const scu_time &rhs) { - return this->hour == rhs.hour && this->minute == rhs.minute; -} - -scu_time scu_time::operator-(const scu_time &rhs) const{ - if (*this < rhs) - size_t lMinute = (this->hour + 24) * 60 + this->minute; - else - size_t lMinute = this->hour * 60 + this->minute; - size_t rMinute = rhs.hour * 60 + rhs.minute; - size_t nHour = (lMinute - rMinute) % 60; - size_t nMinute = (lMinute - rMinute) - nHour * 60; - return scu_time(nHour, nMinute); -} - -bool scu_time::operator<(const scu_time &rhs) const { - if (this->hour > rhs.hour) { - return false; - } else { - if (this->minute >= rhs.minute) { - return false; - } else { - return true; - } - } -} - -bool scu_time::operator<=(const scu_time &rhs) const { - if (this->hour > rhs.hour) { - return false; - } else { - if (this->minute > rhs.minute) - return false; - else - return true; - } -} - -unsigned scu_time::toSeconds() { - return this->hour * 3600 + this->minute * 60; -} - -scu_time scu_time::toScutime(const muduo::Timestamp ×tamp){ - long allSeconds = std::stol(timestamp.toString()); - int seconds = allSeconds % 86400; - size_t hour = seconds / 3600; - size_t minute = (seconds - hour * 3600) / 60; - if(hour >= 16) - hour -= 16; - else - hour += 8; - return scu_time(hour, minute); -} - - diff --git a/include/ServerBase.hpp b/include/ServerBase.hpp deleted file mode 100644 index 70e45db..0000000 --- a/include/ServerBase.hpp +++ /dev/null @@ -1,45 +0,0 @@ -// -// Created by XM on 2021/5/18. -// - -#ifndef PRO_SERVERBASE_HPP -#define PRO_SERVERBASE_HPP - -#pragma once - -#include - -struct scu_date { - size_t week; - size_t day; -}; - -class scu_time { - -private: - size_t hour; - size_t minute; - -public: - - scu_time(size_t h, size_t m) : hour(h), minute(m) {} - - scu_time(const scu_time &that) : hour(that.hour), minute(that.minute) {} - - scu_time operator-(const scu_time &rhs) const; - - bool operator<(const scu_time& rhs) const; - - bool operator=(const scu_time &rhs); - - bool operator<=(const scu_time &rhs) const; - - unsigned toSeconds(); - - static scu_time toScutime(const muduo::Timestamp ×tamp) ; - - -}; - - -#endif //PRO_SERVERBASE_HPP diff --git a/include/Telemeter.hpp b/include/Telemeter.hpp deleted file mode 100644 index 3a4c876..0000000 --- a/include/Telemeter.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef SRC_TELEMETER_H -#define SRC_TELEMETER_H - -#pragma once - -#include "fmt/core.h" - -#include -#include - -enum class LoadLevel : uint8_t -{ - untapped = 0, //no client dispatched on this mirror - light = 1, //[0% - 50%] - medium = 2, //[50% - 80%] - heavy = 3, //[ >= 80%] -}; - -static std::string tostring(LoadLevel ll) -{ - switch (ll) - { - case LoadLevel::untapped: return "untapped"; - case LoadLevel::light: return "light"; - case LoadLevel::medium: return "medium"; - case LoadLevel::heavy: return "heavy"; - default: return "undefined"; - } -} - - -//POD type -struct DetailLoadState -{ - uint8_t mem_load, serve_load, net_load_, reserve_seg_; -}; - -#ifdef SRC_CENTER_H -//center的setting, POD type -struct Setting -{ - uint mir_load_record_interval_; //记录mirror负载到缓存的间隔(按照心跳包的个数来计数), 从配置文件中读 - uint mir_dblog_interval_; //将mirror负载缓存更新到数据库(数据文件)的间隔(缓存了这么多之后打一次log), 从配置文件中读 - uint mir_max_disbeat_time_; //多少个心跳轮无心跳视为断线 - uint cli_login_cache_time_; //清空一个cli登录缓冲的时间 - uint load_balance_interval_; //多少个cli启动后运行一次负载均衡调度算法 - uint clear_mirs_data_time_; //自0点开始何时清空一次mir_data中的信息 - //unsigned long reserve_seg_; //保留段 -}; -//第一字段为60表示一分钟(60个心跳包)记录一次mir的负载情况, -//第二字段为5表示5分钟(缓存5次)输出到遥测数据库一次 - -const constexpr uint _permanent_thread_num_ = 4U; //center的常驻线程数量 - -#endif - -#ifdef SRC_MIRROR_H -//mirror的setting, POD type -struct Setting -{ - int center_ip_; - //int backup_center_ip_; - uint8_t mir_beat_interval_; - uint8_t //数据库ip? -}; -#endif - -#define RESERVE_SEGMENG_INIT_VALUE 0U - -namespace telemeter -{ - const constexpr char* klog_file = "TelemeterLog.txt"; //临时的遥测日志文件 - -#ifdef SRC_CENTER_H - //双缓冲配置表解决一写多读线程安全问题 - static Setting _set_cache_one = {60, 5, 15, 60, 20, 0}; - static Setting _set_cache_two = {60, 5, 15, 60, 20, 0}; - //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 - static Setting* setting = &_set_cache_one; - static Setting* setting_copy = &_set_cache_two; - - //将配置信息返回成一个字符串输出 - // static auto settting_info = [](Setting* set = telemeter::setting) -> std::string - // { - // return fmt::format("mir load record interval: -{0}\n \ - // nmir database log interval: -{1}\n \ - // mir max disbeat time: -{2}\n \ - // cli login cache time: -{3}\n \ - // load balance interval: -{4}\n \ - // clear mirs data time: -{5}", - // set->mir_load_record_interval_, - // set->mir_dblog_interval_, - // set->mir_max_disbeat_time_, - // set->cli_login_cache_time_, - // set->load_balance_interval_, - // set->clear_mirs_data_time_); - // }; -#endif - -#ifdef SRC_MIRROR_H - - -#endif - //获取本机负载情况的函数, 需要统计空闲内存占比, cpu负载, 空闲磁盘占比 - //LoadLevel getLocalLoadLevel(); - - //int getLocalMemLoad(); - //int getLocalSevLoad(); - //int getLocalNetLoad(); -} - - - - - - - - -#endif //SRC_TELEMETER_H \ No newline at end of file diff --git a/include/Udp.hpp b/include/Udp.hpp deleted file mode 100644 index 7956704..0000000 --- a/include/Udp.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef SRC_UDP_H -#define SRC_UDP_H - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -//暂时以int表示ip, 有需要则封装成类 -using IP = int; - -namespace port -{ - const constexpr size_t kCLI_LOGIN_ = 20800; - const constexpr size_t kCLI_BEAT_ = 20801; - const constexpr size_t kMIR_BEAT_ = 20802; - const constexpr size_t kINS_MSG_ = 20803; -} - -namespace protocal -{ - //以字节计算的每个包的大小和协议中每一部分的大小, 二级缩进的和应该等于第一级缩进 - const constexpr size_t kCLI_LOGIN_PACSIZE_ = 8; - const constexpr size_t kCLI_LOGIN_UID_ = 7; - const constexpr size_t kCLI_LOGIN_STATE_ = 1; - - const constexpr size_t kCENT_RESPONSE_PACSIZE_ = 4; - - const constexpr size_t kMIR_BEAT_PACSIZE_ = 8; - const constexpr size_t kMIR_BEAT_IP_ = 4; - const constexpr size_t kMIR_BEAT_LOAD_ = 4; -} - -#endif //SRC_UDP_H - -/* -class IP -{ -private: - union //IP地址共占4个字节 - { - struct //这是一个由4个字节构成的匿名结构体 - { - unsigned char seg0; - unsigned char seg1; - unsigned char seg2; - unsigned char seg3; - }; //4字节的IP地址可以看作4部分,每部分1字节 - unsigned int address; //4字节的IP地址可以看成一个4字节的整体 - }; -public: - IP(int=0,int=0,int=0,int=0); //构造函数 - void showIP(); //用四段法显示IP地址 - bool sameSubnet(const IP &ip, const IP &mark); //判断是否处于同一子网 - char whatKind(); //返回属于哪一类网络 -}; - -原文链接:https://blog.csdn.net/chongshangyunxiao321/article/details/51055658 -*/ diff --git a/include/boost/any.hpp b/include/boost/any.hpp deleted file mode 100644 index 9c2789c..0000000 --- a/include/boost/any.hpp +++ /dev/null @@ -1,342 +0,0 @@ -// See http://www.boost.org/libs/any for Documentation. - -#ifndef BOOST_ANY_INCLUDED -#define BOOST_ANY_INCLUDED - -#if defined(_MSC_VER) -# pragma once -#endif - -// what: variant type boost::any -// who: contributed by Kevlin Henney, -// with features contributed and bugs found by -// Antony Polukhin, Ed Brey, Mark Rodgers, -// Peter Dimov, and James Curran -// when: July 2001, April 2013 - 2020 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost -{ - class any - { - public: // structors - - BOOST_CONSTEXPR any() BOOST_NOEXCEPT - : content(0) - { - } - - template - any(const ValueType & value) - : content(new holder< - BOOST_DEDUCED_TYPENAME remove_cv::type>::type - >(value)) - { - } - - any(const any & other) - : content(other.content ? other.content->clone() : 0) - { - } - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - // Move constructor - any(any&& other) BOOST_NOEXCEPT - : content(other.content) - { - other.content = 0; - } - - // Perfect forwarding of ValueType - template - any(ValueType&& value - , typename boost::disable_if >::type* = 0 // disable if value has type `any&` - , typename boost::disable_if >::type* = 0) // disable if value has type `const ValueType&&` - : content(new holder< typename decay::type >(static_cast(value))) - { - } -#endif - - ~any() BOOST_NOEXCEPT - { - delete content; - } - - public: // modifiers - - any & swap(any & rhs) BOOST_NOEXCEPT - { - placeholder* tmp = content; - content = rhs.content; - rhs.content = tmp; - return *this; - } - - -#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES - template - any & operator=(const ValueType & rhs) - { - any(rhs).swap(*this); - return *this; - } - - any & operator=(any rhs) - { - rhs.swap(*this); - return *this; - } - -#else - any & operator=(const any& rhs) - { - any(rhs).swap(*this); - return *this; - } - - // move assignment - any & operator=(any&& rhs) BOOST_NOEXCEPT - { - rhs.swap(*this); - any().swap(rhs); - return *this; - } - - // Perfect forwarding of ValueType - template - any & operator=(ValueType&& rhs) - { - any(static_cast(rhs)).swap(*this); - return *this; - } -#endif - - public: // queries - - bool empty() const BOOST_NOEXCEPT - { - return !content; - } - - void clear() BOOST_NOEXCEPT - { - any().swap(*this); - } - - const boost::typeindex::type_info& type() const BOOST_NOEXCEPT - { - return content ? content->type() : boost::typeindex::type_id().type_info(); - } - -#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS - private: // types -#else - public: // types (public so any_cast can be non-friend) -#endif - - class BOOST_SYMBOL_VISIBLE placeholder - { - public: // structors - - virtual ~placeholder() - { - } - - public: // queries - - virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0; - - virtual placeholder * clone() const = 0; - - }; - - template - class holder -#ifndef BOOST_NO_CXX11_FINAL - final -#endif - : public placeholder - { - public: // structors - - holder(const ValueType & value) - : held(value) - { - } - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - holder(ValueType&& value) - : held(static_cast< ValueType&& >(value)) - { - } -#endif - public: // queries - - const boost::typeindex::type_info& type() const BOOST_NOEXCEPT BOOST_OVERRIDE - { - return boost::typeindex::type_id().type_info(); - } - - placeholder * clone() const BOOST_OVERRIDE - { - return new holder(held); - } - - public: // representation - - ValueType held; - - private: // intentionally left unimplemented - holder & operator=(const holder &); - }; - -#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS - - private: // representation - - template - friend ValueType * any_cast(any *) BOOST_NOEXCEPT; - - template - friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT; - -#else - - public: // representation (public so any_cast can be non-friend) - -#endif - - placeholder * content; - - }; - - inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT - { - lhs.swap(rhs); - } - - class BOOST_SYMBOL_VISIBLE bad_any_cast : -#ifndef BOOST_NO_RTTI - public std::bad_cast -#else - public std::exception -#endif - { - public: - const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE - { - return "boost::bad_any_cast: " - "failed conversion using boost::any_cast"; - } - }; - - template - ValueType * any_cast(any * operand) BOOST_NOEXCEPT - { - return operand && operand->type() == boost::typeindex::type_id() - ? boost::addressof( - static_cast::type> *>(operand->content)->held - ) - : 0; - } - - template - inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT - { - return any_cast(const_cast(operand)); - } - - template - ValueType any_cast(any & operand) - { - typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; - - - nonref * result = any_cast(boost::addressof(operand)); - if(!result) - boost::throw_exception(bad_any_cast()); - - // Attempt to avoid construction of a temporary object in cases when - // `ValueType` is not a reference. Example: - // `static_cast(*result);` - // which is equal to `std::string(*result);` - typedef BOOST_DEDUCED_TYPENAME boost::conditional< - boost::is_reference::value, - ValueType, - BOOST_DEDUCED_TYPENAME boost::add_reference::type - >::type ref_type; - -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable: 4172) // "returning address of local variable or temporary" but *result is not local! -#endif - return static_cast(*result); -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif - } - - template - inline ValueType any_cast(const any & operand) - { - typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; - return any_cast(const_cast(operand)); - } - -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - template - inline ValueType any_cast(any&& operand) - { - BOOST_STATIC_ASSERT_MSG( - boost::is_rvalue_reference::value /*true if ValueType is rvalue or just a value*/ - || boost::is_const< typename boost::remove_reference::type >::value, - "boost::any_cast shall not be used for getting nonconst references to temporary objects" - ); - return any_cast(operand); - } -#endif - - - // Note: The "unsafe" versions of any_cast are not part of the - // public interface and may be removed at any time. They are - // required where we know what type is stored in the any and can't - // use typeid() comparison, e.g., when our types may travel across - // different shared libraries. - template - inline ValueType * unsafe_any_cast(any * operand) BOOST_NOEXCEPT - { - return boost::addressof( - static_cast *>(operand->content)->held - ); - } - - template - inline const ValueType * unsafe_any_cast(const any * operand) BOOST_NOEXCEPT - { - return unsafe_any_cast(const_cast(operand)); - } -} - -// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. -// Copyright Antony Polukhin, 2013-2020. -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#endif diff --git a/include/center/CenterConfig.txt b/include/center/CenterConfig.txt deleted file mode 100644 index cdb0999..0000000 --- a/include/center/CenterConfig.txt +++ /dev/null @@ -1,48 +0,0 @@ -next_read_this_file_interval: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) - -mir_load_record_interval: [60] //多少次收到心跳包后记录一次mirror的负载情况 -mir_load_dblog_interval: [5] //多少次记录后, 一次性输出到遥测数据库 -mir_max_disbeat_time: [15] //该数字乘上心跳间隔表示多少秒钟无心跳视为断线, 最大128 -cli_login_cache_time: [60]s //多少秒内收到重复的cli登录请求视为包延迟到达 - -变量命名:参照muduo库, - 类型名都是大写开头驼峰命名 - 类内函数名都是小写开头驼峰命名 - 变量名都以小写字母下划线命名 - 类内变量都额外加一个下划线结尾 - 常量额外以k开头 - 希望对外匿名的变量以下划线开头 - -建议:全局函数除了一个单词能表明含义的情况均以大写字母开头的驼峰命名 - -center启动流程 - 读取配置文件, 读入各项数据到内存中, 没有配置文件则用默认值{60, 5, 60, 0}初始化 - 提交任务: - 1.定时读取配置文件给telemeter的备份缓冲setting, 读取完成后交换主备份setting指针的值 - 2.开启3个 udp线程加入到线程池, 1. 收cli登录信息并回复, 调度算法在这里 2. 收mir心跳 3.收即时消息 - 3.loop启动 - 4.可能需要链接数据库 - 5.定时(每天0点)清空所有cli_ip和树形结构中的信息(类似重启), 触发条件是每晚各种东西都会断电掉线, 否则不需要 - -cli登录流程: - cli发送udp给center的20800端口 - ->center在cookie[无锁队列]中检查有无历史登录痕迹[读] - ->有:视为包延迟到达, 不做处理 - ->无:回复当前可用mirr地址[即all_mir], 在all_cli[哈希表]中查询是否出现过该UUID - //{如果把以下两行的任务改为提交给线程池执行而不在io线程, 在多个cli短时间内一同登录时可能会出现同时写的问题?} - ->有:说明是今日重新连接, 在mirs_data中校正该ip所分配mir的信息, 需要遍历并且修改 - ->无:说明是今天首次连接, 在mirs_data中记录该数据 - ->在队列尾部新加入该缓冲, 设置cli_login_cache_pop_interval后pop掉队头的任务 - ->输出日志, 包括cli_iD, timestamp, mir_ip, - -mir登录及心跳流程: - center在20802接受到mir心跳的udp包, 该函数有一个静态变量all_beat_count_ - ->在mirs_data中检查有无这个mir的ip - ->无, 是新的mir登录, 在mirs_data中记录该数据, 创建新的mirDescript, 标记其状态为untapped, beat_count = - ->有, 是mir的心跳, 给该mirror的beat_重置为mir_max_disbeat_time, 记录负载情况到load_cache, 同时给all_beat_count+1, 判断此时all_beat_count的值, 若其 >= mirs_data.size() - 1 - ->是, 给mirs_data中每一个value的beat_count - 1, 判断此时 - 1 之后的beat_count == 0 ? 是则说明掉线, 不是则说明正常, 记录负载情况到load_cache中, 如果load_cache满则一次写入数据库并清空 - //缺点在于一次掉线多个... - -message流程 - center在20803收到message的心跳包(一个布尔量), 给mirs_data内所有key发送一个布尔量, 完成 - diff --git a/include/center/MirDescript.cpp b/include/center/MirDescript.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/include/center/TcpEcho.cpp b/include/center/TcpEcho.cpp deleted file mode 100644 index 6620634..0000000 --- a/include/center/TcpEcho.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "TcpEcho.h" - -using std::placeholders::_1; -using std::placeholders::_2; -using std::placeholders::_3; - -//using namespace muduo; -//using namespace muduo::net; - -EchoServer::EchoServer(muduo::net::EventLoop* loop, - const muduo::net::InetAddress& listenAddr) - : server_(loop, listenAddr, "EchoServer") -{ - server_.setConnectionCallback( - std::bind(&EchoServer::onConnection, this, _1)); - server_.setMessageCallback( - std::bind(&EchoServer::onMessage, this, _1, _2, _3)); -} - -void EchoServer::start() -{ - server_.start(); -} - -void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn) -{ -// LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> " -// << conn->localAddress().toIpPort() << " is " -// << (conn->connected() ? "UP" : "DOWN"); -} - -void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn, - muduo::net::Buffer* buf, - muduo::Timestamp time) -{ -// muduo::string msg(buf->retrieveAllAsString()); -// LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, " -// << "data received at " << time.toString(); -// conn->send(msg); -} diff --git a/include/center/center.cpp b/include/center/center.cpp deleted file mode 100644 index c887a49..0000000 --- a/include/center/center.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "center.h" - -void center::start() -{ - //假设udp namespace 下的 recv和send已经正常 - //任务队列最大数量 - pool_.setMaxQueueSize(30); - pool_.start(_permanent_thread_num_ + 5); //这里默认四核八线程, 也可以用std::hard_ware_concurrency()确定 - - //提交定时读取配置文件的任务,监听cli登录, mir心跳的任务 - this->pool_.run( [this](){ read_config(); }); - this->pool_.run( [this](){ wait_cli_login(); }); - this->pool_.run( [this](){ listen_mir_beat(); }); - //this->pool.run( [this](){ clear_mirs_data(); }); - - //可能需要设置一段时间内进行日志输出的文件和文件路径 - -} - -void center::read_config() -{ - //或者放到center中作为一个变量 - static std::string config_file_path; - //或者 - //static std::fstream config_file; - - //可以使用如下形式的定义 - //static auto read_data_infile/copy/swap = [=](...){ ... }; - - while(true) - { - Setting set_in_file{}; - - //读取配置文件 - //read_data_in(config_file_path, set_in_file); - - //复制到配置副本中 - //copy(set_in_file, *setting_copy); - - //交换主副配置指针 - //swap(setting_copy, setting); //atomic operation - - //sleep(set_in_file.next_read_intrerval); - } -} - -void center::wait_cli_login() -{ - //用于接收数据的缓冲区 - //char* buffer[xxx_len]; - //flush(buffer) - //current_available_mir - - while(true) - { - //udp::recv(port, buffer ...); - - //按照协议格式进行解析, 并且得到ip等其他信息 - //auto [cli_id, login_count, state] = msg[...] - - //登录或者重新连接 - // if(!cookie_.contains(cli_id)) - // { - // //重新连接 - // if(all_cli_.contains(cli_id)) - // { - // correct_info(mirs_data_, cli_id); - // } - // else //首次链接 - // { - // record_info(mirs_data, cli_id); - // } - // cookie_.cache_login_info(cli_id); - // dblog(cli_login_event, cli_id); - // } - // else - // { - // //延迟到达不做处理 - // continue; - // } - // flush(buffer); - } -} - diff --git a/include/center/center.h b/include/center/center.h index 22c2874..8c29de0 100644 --- a/include/center/center.h +++ b/include/center/center.h @@ -1,6 +1,6 @@ #ifndef SRC_CENTER_H #define SRC_CENTER_H - +#pragma once #include "netinet/in.h" #include "sys/socket.h" #include "arpa/inet.h" @@ -16,6 +16,7 @@ #include #include +#include #include diff --git a/include/center/main.cpp b/include/center/main.cpp deleted file mode 100644 index a2d2b42..0000000 --- a/include/center/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ - - -#include "TcpEcho.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/EventLoop.h" - -#include - -// using namespace muduo; -// using namespace muduo::net; - -int main() -{ - LOG_INFO << "pid = " << getpid(); - muduo::net::EventLoop loop; - muduo::net::InetAddress listenAddr(2007); - EchoServer server(&loop, listenAddr); - - server.start(); - loop.loop(); -} diff --git a/include/center_head b/include/center_head index c6103e0..5d423c8 100644 --- a/include/center_head +++ b/include/center_head @@ -1,3 +1,5 @@ +#pragma once + #include "Center/center.h" #include "Center/MirDescript.h" #include "Center/TcpEcho.h" \ No newline at end of file diff --git a/include/common_head b/include/common_head index b4e1b77..d4b71d9 100644 --- a/include/common_head +++ b/include/common_head @@ -1,3 +1,5 @@ +#pragma once + #include "Common/ServerBase.hpp" #include "Common/Telemeter.hpp" #include "Common/Udp.hpp" \ No newline at end of file diff --git a/include/db_control/db_control.cpp b/include/db_control/db_control.cpp deleted file mode 100644 index 85d2080..0000000 --- a/include/db_control/db_control.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include -#include "../mirror/lesson.hpp" -#include "../ServerBase.hpp" -#include -#include "../mirror/ClassMes.hpp" -#include -#include - -namespace db_control { - - void check_week_and_day(nanodbc::connection conn, scu_date &date) { - if (date.day == 7) { - date.week += 1; - date.day = 1; - } else { - date.day += 1; - } - } - - /* - * param CCmap uuid->ClassMes - * param skjc 上课节次 - * - */ - - void - query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, - scu_date *date, Uuid id = -1) { - size_t week = date->week; //第几周 - size_t day = date->day; //星期几 - bool new_client = false; - std::string find_stmt{}; - - std::string uuid_stmt{}; - - if (id < 0) { - auto iter = CCmap.begin(); - uuid_stmt += "( U.uuid = " + std::to_string(iter->first); - for (auto iter = CCmap.begin(); iter != CCmap.end(); iter++) { - uuid_stmt += " OR\n U.uuid = "; - uuid_stmt += std::to_string(iter->first); - } - uuid_stmt += ") AND\n" - } else { - uuid_stmt = std::string("U.uuid = " + std::to_string(id)); - new_client = true; - } - auto get_find_stmt = [&](size_t skJc) { - find_stmt = std::string("SELECT\n" - "U.uuid AS uuid,\n" - "P.kch AS `kch`,\n" - "P.kxh AS `kxh`,\n" - "K.kcm AS `kcm`,\n" - "P.jsxm AS `jsxm`,\n" - "P.jxdd AS `jdxx`,\n" - "p.jsszxqh AS `jsszxqh`\n" - "FROM\n" - "uuid_jxdd AS U\n" - "INNER JOIN pksj AS P ON U.jxdd = P.jxdd AND U.jsszxqh = P.jsszxqh\n" - "INNER JOIN kcb AS K ON P.kch = K.kch\n" - "WHERE\n" - + uuid_stmt.c_str() + - "P.sksj <= " + skJc + " AND\n" - "P.sksj+P.cxjc\t >= " + skJc + " AND\n" - "P.skxq = " + day + " AND\n" - "SUBSTR(qsz," + - week + ",1)=\'1\'"); - }; - - auto update_map = [&](size_t jc, bool first, bool new_cli = false;) { - get_find_stmt(skjc); - try { - nanodbc::result find_row = nanodbc::execute(conn, find_stmt); - for (; find_row.next();) { - int uid = find_row.get(0); - - if (new_cli) { - int xqh = find_row.get(6); - std::string dd = find_row.get(5); - ClassPlace cp; - cp.jxdd_ = dd; - cp.jsszxqh = xqh; - ClassMes ci; - ci.classPlace_ = cp; - CCmap.insert(std::make_pair(id, ci)); - } - - if (CCmap.find(uid) != CCmap.end()) { - lesson les = lesson(find_row.get(1), find_row.get(2), - find_row.get(3), find_row.get(4), - find_row.get(5)); - if (first) - CCmap.at(uid).lesson_1 = les; - else - CCmap.at(uid).lesson_2 = les; - } else { - continue; - } - } - } catch (const std::exception &e) { - std::cerr << e.what() << std::endl; //更换为日志报错 - } - }; - -// 更新当前节次 - update_map(skjc, true, new_client); - if (two_lesson) { -// 更新下一节次 - update_map(skjc + 1, false, new_client); - } - - } diff --git a/include/json_control/json_control.cpp b/include/json_control/json_control.cpp deleted file mode 100644 index 665e574..0000000 --- a/include/json_control/json_control.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include "../mirror/ClassMes.hpp" -#include -#include - -namespace json_control{ - -void getJson(rapidjson::Writer&writer, const Message& mes){ - //开启对象 - writer.StartObject(); - //title - writer.Key("Title"); - writer.String(mes.title.c_str()); - - //text - writer.Key("text"); - writer.String(mes.text.c_str()) - - //expiretime - writer.Key("expireTime"); - writer.String(mes.expireTime.c_str()); - - //结束对象 - writer.EndObject(); -} - -void getJson(rapidjson::Writer&writer, const lesson &les){ - //开始对象 - writer.StartObject(); - - //课程号 - writer.Key("kch"); - writer.String(les.kch_.c_str()); - - //课序号 - writer.Key("kxh"); - writer.Int(les.kxh_.c_str()) - - //课程名 - writer.Key("kcm"); - writer.String(les.kcm_.c_str()); - - //教师姓名 - writer.Key("jsxm"); - writer.String(les.jsxm_.c_str()); - - //教学地点 - writer.Key("jxdd"); - writer.String(les.jxdd_.c_str()); - - //结束对象 - writer.EndObject(); -} -void getJsonInfo(const ClassMes& mes, const muduo::Timestamp& timestamp) { - rapidjson::StringBuffer strBuf; - rapidjson::Writer writer(strBuf); - //声明strBuf与writer对象 - - //开启json对象 - writer.StartObject(); - - //时间戳 - writer.Key("time"); - writer.String(timestamp.toString().c_str()); - - //图像的url - writer.Key("image_url"); - writer.String(mes.image_url.c_str()); - - //消息队列 - writer.Key("message"); - //开启数组 - writer.StartArray(); - for (auto iter = mes.messages.begin(); iter != mes.messages.end(); iter++) { - getJson(writer, *iter); - } - //结束数组 - writer.EndArray(); - - //第一节课信息 - writer.Key("event"); - - getJson(writer, mes.lesson_1); - - //第二节课信息 - writer.Key("next_event"); - - getJson(writer, mes.lesson_2); - - //需要更新 - writer.Key("needUpdate"); - writer.Bool(true); - - //结束json对象 - writer.EndObject(); - - std::string json = strBuf.GetString(); - - return json; -} - -}//End namespace of json_control diff --git a/include/mirror/Cli.hpp b/include/mirror/Cli.hpp deleted file mode 100644 index 03fbd77..0000000 --- a/include/mirror/Cli.hpp +++ /dev/null @@ -1,14 +0,0 @@ -// -// Created by XM on 2021/5/20. -// - -#pragma once - -namespace Cli{ - using Uuid = unsigned int; -} - -struct ClassPlace final{ - std::string jxdd_; //教室地点 - unsigned jsszxqh; //教室所在校区号 -}; diff --git a/include/mirror/CliDescript.hpp b/include/mirror/CliDescript.hpp index 0796290..a4beb73 100644 --- a/include/mirror/CliDescript.hpp +++ b/include/mirror/CliDescript.hpp @@ -12,7 +12,7 @@ namespace Cli{ struct CliDes{ Cli::Uuid id; - size_t campus; + int campus; std::string stamp; }; diff --git a/include/mirror/Message.hpp b/include/mirror/Message.hpp index f8dc38d..dabc795 100644 --- a/include/mirror/Message.hpp +++ b/include/mirror/Message.hpp @@ -2,9 +2,21 @@ #include "CliDescript.hpp" -struct Message{ +struct Message { std::string title; std::string text; - int expireTime;//seconds + size_t expireTime;//seconds }; +namespace std { + template<> + struct hash : public __hash_base { + size_t operator()(const Message &rhs) const noexcept //这个const noexpect一定要写上去 + { + return ((std::hash()(rhs.title) << 1) ^ + (std::hash()(rhs.text) << 1) ^ + (std::hash()(rhs.expireTime))); //当然,可以使用其他的方式来组合这个哈希值, + //这里是cppreference里面的例子,产生的数够乱就行。 + } + }; +} \ No newline at end of file diff --git a/include/mirror/Mirror.cpp b/include/mirror/Mirror.cpp deleted file mode 100644 index dcd2a27..0000000 --- a/include/mirror/Mirror.cpp +++ /dev/null @@ -1,408 +0,0 @@ -#include "Mirror.hpp" - - -void Mirror::start() { -//任务队列最大数量 - pool_.setMaxQueueSize(30); - //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 - pool_.start(static_cast(2 * std::thread::hardware_concurrency())); - auto thd_start = [&](const char *info) { - std::clog << "thread start: " << info << std::endl; - }; - - // db_config 初始化 - nanodbc::connection conn = nanodbc::connection(db_dsn, db_name, db_passwd); - - //读取配置文件 - this->pool_.run([this]() { read_config(); }); - thd_start("read config"); - //发送负载情况 - this->pool_.run([this]() { update_data_info(); }); - thd_start("update data info"); - //更新数据缓存 - this->pool_.run([this]() { update_clis_data(); }); - thd_start("updae clients data"); - - //输出日志 -} - -void Mirror::read_config() { - -// 后可以考虑使用json格式 - static std::string config_file_path{"MirrorConfig.txt"}; - static std::ifstream in{config_file_path, std::ios::in}; - Setting set{}; - memset(&set, 0, sizeof(Setting)); - size_t next_read_interval{0}; - - auto read_data = [&]() { - if (!in.is_open()) - in.open(config_file_path, std::ios::in); - std::string line{}; - while (in.good()) { - std::getline(in, line, '\n'); - if (line.size() < 2 || line.front() == '/') - continue; - else if (line.find("next_read") != std::string::npos) - next_read_interval = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - else if (line.find("mir_heart") != std::string::npos) - set.mir_heart_beat_interval_ = std::stoi( - std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - else if (line.find("mir_load") != std::string::npos) - set.mir_load_report_interval_ = std::stoi(std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - else if (line.find("cli_class") != std::string::npos) - set.cli_class_info_cache_time_ = std::stoi( - std::string(line.find_first_of('[') + 1, line.find_first_of(']'))); - } - }; - - auto swap = [](Setting *src, Setting *dst) { - Setting *tmp = dst; - dst = src; - src = tmp; - }; - - while (true) { - //读取配置文件 - read_data(); - - //复制到配置副本中 - memcpy(telemeter::setting_copy, &set, sizeof(Setting)); - - //交换主副配置指针 - swap(telemeter::setting_copy, telemeter::setting); //atomic operation - - //挂起该进程 - sleep(next_read_interval * 1000); - } -} - -void Mirror::update_data_info() { -// 发送ip地址 - using Server::IP; - IP center_ip{0}; //通过配置文件 - IP this_ip{0};//unknown - - DetailLoadState dtlLoadState{}; -// 定义计算服务器负载情况的函数 - auto cal_ser_load = [&]() -> uint8_t { - return 0; - }; - -// 定义计算内存负载情况的函数 - auto cal_mem_load = [&]() -> uint8_t { - std::ifstream in; - std::string filename = ""; - return 0; - }; - -// 定义计算网络负载情况的函数 - auto cal_net_load = [&]() -> uint8_t { - return 0; - }; - - auto get_packet = [&](IP, DetailLoadState DtlLoadState) { - center_ip; - this_ip; - //calculate ServerLoad - uint8_t serverLoad = cal_ser_load(); - DtlLoadState.serve_load = serverLoad; - //calculate MemoryLoad - uint8_t memLoad = cal_mem_load(); - DtlLoadState.mem_load = memLoad; - //calculate NetworkLoad - uint8_t netLoad = cal_net_load(); - DtlLoadState.net_load_ = netLoad; - - return "12345678"; - }; - - - - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; -// 设置发送端口 - servaddr.sin_port = htons(port::kMIR_BEAT_); -// 设置发送ip - servaddr.sin_addr.s_addr = inet_addr(center_ip); - -// 发送缓存 - char *packet = "\0"; - -// 更新间隔 - size_t time = 60; -// 发送的息 - char send_buf[8] = {0}; - -//线程主循环 - while (true) { - - if (time == telemeter::setting->mir_load_report_interval_) { - //to_string(8byte) = 4+1+1+1+1 true/false - //更新负载情况 - send_buf = get_packet(this_ip, dtlLoadState); - time = 1; - } - -// 发送‘心跳包’ - sendto(sock, sendbuf, strlen(sendbuf), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); - // 重置缓冲 - memset(sendbuf, 0, sizeof(sendbuf)); - // 统计发送心跳包次数 - time++; - //心跳包频率 - sleep(telemeter::setting->mir_heart_beat_interval * 1000); - } -} - -//待修改 -void Mirror::on_message(muduo::net::TcpConnectionPtr conn, - std::string msg, - muduo::Timestamp time) { - //比较时间戳, 相等, 无事发生 - if (equal(time, *this->wj_timestamp_) { - //发送不需要更新的json - conn->send(CliDescript::NO_NEED_UPDATE); - } else //这里的逻辑需要完善 - { - //回复的内容 - JsonValue reply(); - //解析msg, 得到uuid - JsonValue pack = JsonParser(msg); - Uuid id = pack["uuid"]; - //查询有无即时消息 - if (message_.front().get_dests().contains(id)); - { - reply["Message"] = message_.front().to_string(); - } - - } - -} - -//多并发 -void Mirror::listen_cli_beat(muduo::net::TcpConnectionPtr &conn, - muduo::net::Buffer *buf, - muduo::Timestamp time) { - //set server.onConnect 连接函数 - this->pool_.run(std::bind(Mirror::on_message, - this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3), - std::move(conn), - std::move(std::string(buf->retrieveAllAsString())), - std::move(time))); -} - -//监听center发送的udp包 -void Mirror::listen_mes() { -// udp - while (true) { - //server.start - - //接收到包 - - //数据库拉取信息 - - //更新信息 - } -} - -//清除mirror->client树信息 -void Mirror::clear_cli_data() { - while (true) { - //每日0点更新.用scu_time更新 - - //sleep()24h - } -} - -//定时拉取数据库信息, 更新时间戳 -void Mirror::update_clis_data() { - //cli-classinfo缓存 - std::unordered_map clis_data; - -// 校园日历 - scu_date sD{1, 1}; - scu_date sD_1{1, 1}; - scu_date *scuDate = &sD; - scu_date *scuDate_copy = &sD_1; - - scu_date scuDate_cache{}; - - scu_time nowTime{0, 0}; - - auto swap_scu_date_ptr = [&]() { - scu_date *tmp = scuDate; - scuDate_copy = scuDate; - scuDate = tmp; - }; - -//写当日date(其实不会出现冲突.但为以后消费者模型做准备工作) - auto update_scu_date = [&]() { -//更新当日上课信息 - db_control::check_week_and_day(conn, scuDate_cache); -//复制至副本 - memcpy(scuDate_copy, &scuDate_cache, sizeof(scu_date)); -//交换指针 - swap_scu_date_ptr(); - }; - -// 判断时间 - auto at_middle = [&](const scu_time &lTime, const scu_time &rTime) { - return (lTime <= nowTime) && (nowTime < rTime); - }; - - auto get_seconds_from_now = [&](const scu_time &time) { - nowTime = scu_time::toScutime(muduo::Timestamp::now()); - return time <= nowTime ? 0 : (time - nowTime).toSeconds(); - }; - - auto query_scu_time = [&](int &xqh, int &jc) -> scu_time { -// 获取迭代器,遍历时间表 - - auto iter1 = this->wj_Time.begin(); - auto iter2 = this->ja_Time.begin(); -// 上课节次,用于返回 - int skjc = 0; - - nowTime = scu_time::toScutime(muduo::Timestamp::now());//获取当前时间,进行分析 - - for (; iter1 != wj_Time.end(); iter1++, iter2++) { - skjc++; - jc = skjc; - if (skjc <= 4) { - if (nowTime <= *iter1) { - xqh = 1; - return scu_time(0, 15); - } else { - if (nowTime <= *iter2) { - xqh = 3; - if (skjc == 4) - return scu_time(2, 40); - else - return scu_time(0, 40); - } else { - continue; - } - } - } else { - if (nowTime <= *iter2) { - xqh = 3; - return scu_time(0, 10); - } else { - if (nowTime <= *iter1) { - xqh = 1; - if (skjc == 9) //晚餐 - return scu_time(1, 30); - else if (skjc == 7) - return scu_time(0, 55); - else if (skjc == 12) - return scu_time(0, 0); - else - return scu_time(0, 45); - } else { - continue; - } - } - } - } - }; - -// 自动计算当前时间 - auto query_clis_data = [&, this]() { - std::unordered_map clis_data_cache_; - bool two_lessons = true; - int xqh = 0; //校区号 - int jc = 0; //时间 - - auto update_uC_map = [](const std::unordered_map &data_map, - std::unordered_map *origin_map, - std::unordered_map *copy_map) { - //赋值 - *copy_map = data_map; -// 交换指针 - auto tmp = copy_map; - copy_map = origin_map; - origin_map = tmp; - }; - - - //获取应当更新的校区号与节次 - scu_time wait_time = query_scu_time(xqh, jc); - - if (jc == 4 || jc == 9 || jc == 12) - two_lessons = false; - size_t wait_second = wait_time.toSeconds(); - if (xqh == 1) { -// 更新值 -// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 - clis_data_cache_ = *(this->wj_clis_data_); -// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 - db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); -// 获取当前时间戳 - muduo::Timestamp nTime = muduo::Timestamp::now(); -// 更新时间戳 - update_timestamp(nTime, wj_timestamp_, wj_timestamp_copy); - // 交换指针 - - update_uC_map(clis_data_cache_, this->wj_clis_data_, this->wj_clis_data_copy); - } else if (xqh == 3) { -// 更新值 - clis_data_cache_ = *ja_clis_data_; -// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 - db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); -// 获取当前时间戳 - muduo::Timestamp nTime = muduo::Timestamp::now(); -// 更新时间戳 - update_timestamp(nTime, ja_timestamp_, ja_timestamp_copy); -// 交换指针 - update_uC_map(clis_data_cache_, this->ja_clis_data_, this->ja_clis_data_copy); - } - - return wait_second; - }; - -// mirror开机时,初始化当时时间 - update_scu_date(); - muduo::Timestamp nTime = muduo::Timestamp::now(); - nowTime = scu_time::toScutime(nTime); - - -// 进入任务线程阶段 - while (true) { -// 挂起. 7.55唤醒 - sleep(get_seconds_from_now(scu_time(7, 55)) * 1000); - - while (true) { - nowTime = scu_time::toScutime(muduo::Timestamp::now());//记录当前时间 - size_t sleepSeconds = 0; - sleepSeconds = query_clis_data(); //更新数据,在函数体内自动计算时间 - - if (sleepSeconds == 0) - break; - //休眠至下一次更新 - sleep(sleepSeconds * 1000); - } - sleep(get_seconds_from_now(scu_time(24, 0)) * 1000); //沉睡至24点 -// 24点更新当日上课信息 - update_scu_date(); - } - - conn.close(); -} - -void Mirror::update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, - muduo::Timestamp *copy_campus_stamp) { - - // 赋值 - *copy_campus_stamp = dataStamp; - -// 交换指针 - auto swap = [](muduo::Timestamp *origin, muduo::Timestamp *copy) { - muduo::Timestamp *tmp = origin; - origin = copy; - copy = tmp; - }; - swap(origin_campus_stamp, copy_campus_stamp); -} - diff --git a/include/mirror/Mirror.hpp b/include/mirror/Mirror.hpp index acc2b27..23dbe42 100644 --- a/include/mirror/Mirror.hpp +++ b/include/mirror/Mirror.hpp @@ -9,6 +9,7 @@ #include #include #include +#include //udp使用 #include @@ -26,6 +27,8 @@ #include #include #include +#include + #include #include @@ -38,16 +41,22 @@ using Cli::Uuid; class Mirror final { struct OldHash { - size_t msg_, course_, event_, next_event_; + size_t url_, event_, next_event_; + std::deque msgs_; bool operator==(const OldHash &x) { - return this->course_ == x.course_ + auto iter1 = msgs_.begin(); + auto iter2 = x.msgs_.begin(); + for(; iter1 != msgs_.end(); iter1++, iter2++){ + if(*iter1 != *iter2) + return false; + } + return this->url_ == x.url_ && this->event_ == x.event_ - && this->msg_ == x.event_ && this->next_event_ == x.next_event_; //最后一位暂时不做比较 } - } + }; private: @@ -67,6 +76,11 @@ class Mirror final { std::unordered_map Class2Campus; std::unordered_map cli_info_; + std::atomic_size_t wj_section; + std::atomic_size_t ja_section; + std::atomic_size_t week; + std::atomic_size_t day; + // 数据库连接 nanodbc::connection conn; // 线程池 @@ -74,11 +88,8 @@ class Mirror final { // 数据库配置相关,仅在程序开始时使用 // 在配置文件获取 - const std::string db_dsn = "MariaDB-server"; - const std::string db_name = "root"; - const std::string db_passwd = "root"; - std::string img_path = "/home/jol"; + const std::string config_file_path{"MirrorConfig.txt"}; //配置文件 std::vector wj_Time = { @@ -119,21 +130,27 @@ class Mirror final { //定时 更新图片与内存信息 void update_pictures_info(); + //定时 更新课程节次信息,包括江安与望江 + void update_course_section(); + + //定时 更新校历信息 + void update_school_calendar(); + //Client相关 void listen_cli_beat(); + //回调查询信息 - static void on_message(const muduo::net::TcpConnectionPtr &conn, + void on_message(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *msg, muduo::Timestamp time); - static void on_disconnected(); - +/* void update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, muduo::Timestamp *copy_campus_stamp); - +*/ //配置文件,初始化等 void init(); diff --git a/include/mirror/MirrorConfig.txt b/include/mirror/MirrorConfig.txt deleted file mode 100644 index 8f88194..0000000 --- a/include/mirror/MirrorConfig.txt +++ /dev/null @@ -1,24 +0,0 @@ -next_read_interval: [600]s //多少秒之后重新读取配置文件, 需要不停机调试则尽量缩短, 但不建议小于30(半分钟) -mir_heart_beat_interval: [1]s //心跳的间隔 -mir_load_report_interval: [60] //多少个心跳包后更新负载情况 -cli_class_info_cache_time: [600]s //课程信息在cli断联后缓存时间, 如果内存紧张可以适当缩短 - - - -mir启动流程 - 启动EventLoop, 启动Server, 清空clis_data - 提交任务 - 定时读取配置文 - 按照更新负载情况的间隔更新load - 心跳任务, 心跳计数器的值从配置表中读取 - 启动等待即时消息的线程 - -cli通过tcp连接 - ->连接:从cookie中寻找缓存, 若无则在clis_data中更新其信息, 从数据库拉取课表信息, 并根据课表信息提交一段时间后重新拉取下节课的任务 - ->查询:目前是多线程操作,单查询比联合查询效率更高(可详细测试),且消耗内存更少.故先查询所在校区号与教室地点.再利用该数据查询课程内容与下节课内容 - ->断线:将clis_data的信息存入缓存, 设置 -Message - 使用者通过管理程序向数据库中插入即时消息的内容和目的地, 然后发送一个简短报文给center, center收到后 -发送udp包给mir, mir接收到包在数据库中读取消息内容和消息目的地和消息过期时间, 将前两者插入到消息队列中并设置定时清空队头的任务 - -//可能的每晚清空新奇重新启动? 有cli彻夜开着吗? diff --git a/include/mirror/Util.hpp b/include/mirror/Util.hpp index fa47122..dafb01b 100644 --- a/include/mirror/Util.hpp +++ b/include/mirror/Util.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -19,42 +20,46 @@ namespace db_control { using Cli::Uuid; - void check_week_and_day(nanodbc::connection conn, scu_date &date); +// void check_week_and_day(nanodbc::connection conn, scu_date &date); /* * param CCmap uuid->ClassMes * param skjc 上课节次 * */ - void - query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, - scu_date *date, Uuid id = -1); + //暂停使用 +// void +// query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, +// scu_date *date, Uuid id = -1); - void query_background(nanodbc::connection conn, std::vector& backgrounds); + void query_background(nanodbc::connection &conn, std::vector& backgrounds); - void update_pic_info(nanodbc::connection conn, wj_clis_cache, const std::string &stamp); + std::string find_pic(nanodbc::connection &conn, Cli::Uuid id); - std::string find_pic(const nanodbc::connection &conn, Cli::Uuid id, const std::string &stamp); + std::deque find_mes(nanodbc::connection &conn, Cli::Uuid id, const std::string &stamp); - std::deque find_mes(const nanodbc::connection &conn, Cli::Uuid id, const std::string stamp); + Lesson find_lesson(nanodbc::connection &conn, Cli::Uuid id, int skjc, const scu_date &date); - Lesson find_lesson(const nanodbc::connection &conn, Cli::Uuid, const std::string& stamp); + int find_campus(nanodbc::connection &conn, Cli::Uuid id); + + scu_date update_calendar(nanodbc::connection &conn, int year, int month, int date); } namespace json_control { + extern std::string no_need_update; void getJson(rapidjson::Writer &writer, const Message &mes); void getJson(rapidjson::Writer &writer, const Lesson &les); - std::string getJsonInfo(const ClassMes &mes, const muduo::Timestamp ×tamp); + std::string getJsonInfo(const ClassMes &mes, const std::string ×tamp); void getIdAndStamp(const std::string& src, Cli::Uuid &id, std::string& stamp); }//End namespace of json_control namespace codec{ - void downPic( const std::string &code,const std::string& path); + void downPic(const std::string& path, const std::string &code); } \ No newline at end of file diff --git a/include/mirror/lesson.hpp b/include/mirror/lesson.hpp index b934dcd..af0a313 100644 --- a/include/mirror/lesson.hpp +++ b/include/mirror/lesson.hpp @@ -18,4 +18,19 @@ struct Lesson final { Lesson() {} -}; \ No newline at end of file +}; + +namespace std { + template<> + struct hash : public __hash_base + { + size_t operator()(const Lesson &rhs) const noexcept //这个const noexpect一定要写上去 + { + return ((std::hash()(rhs.kch_) << 1) ^ + std::hash()(rhs.kxh_) ^ (std::hash()(rhs.kcm_) << 1) ^ + (std::hash()(rhs.jsxm_) << 1) ^ + (std::hash()(rhs.jxdd_) << 1)); + + } + }; +} diff --git a/include/mirror_head b/include/mirror_head index 93dc092..7e916c5 100644 --- a/include/mirror_head +++ b/include/mirror_head @@ -1,7 +1,9 @@ +#pragma once + #include "Mirror/ClassMes.hpp" #include "Mirror/CliDescript.hpp" #include "Mirror/Lesson.hpp" #include "Mirror/Message.hpp" #include "Mirror/Mirror.hpp" +#include "Mirror/BackGround.hpp" #include "Mirror/Util.hpp" -#include "Mirror/BackGround.hpp" \ No newline at end of file diff --git a/include/muduo/base/AsyncLogging.cc b/include/muduo/base/AsyncLogging.cc deleted file mode 100644 index 0f82444..0000000 --- a/include/muduo/base/AsyncLogging.cc +++ /dev/null @@ -1,136 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/AsyncLogging.h" -#include "muduo/base/LogFile.h" -#include "muduo/base/Timestamp.h" - -#include - -using namespace muduo; - -AsyncLogging::AsyncLogging(const string& basename, - off_t rollSize, - int flushInterval) - : flushInterval_(flushInterval), - running_(false), - basename_(basename), - rollSize_(rollSize), - thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"), - latch_(1), - mutex_(), - cond_(mutex_), - currentBuffer_(new Buffer), - nextBuffer_(new Buffer), - buffers_() -{ - currentBuffer_->bzero(); - nextBuffer_->bzero(); - buffers_.reserve(16); -} - -void AsyncLogging::append(const char* logline, int len) -{ - muduo::MutexLockGuard lock(mutex_); - if (currentBuffer_->avail() > len) - { - currentBuffer_->append(logline, len); - } - else - { - buffers_.push_back(std::move(currentBuffer_)); - - if (nextBuffer_) - { - currentBuffer_ = std::move(nextBuffer_); - } - else - { - currentBuffer_.reset(new Buffer); // Rarely happens - } - currentBuffer_->append(logline, len); - cond_.notify(); - } -} - -void AsyncLogging::threadFunc() -{ - assert(running_ == true); - latch_.countDown(); - LogFile output(basename_, rollSize_, false); - BufferPtr newBuffer1(new Buffer); - BufferPtr newBuffer2(new Buffer); - newBuffer1->bzero(); - newBuffer2->bzero(); - BufferVector buffersToWrite; - buffersToWrite.reserve(16); - while (running_) - { - assert(newBuffer1 && newBuffer1->length() == 0); - assert(newBuffer2 && newBuffer2->length() == 0); - assert(buffersToWrite.empty()); - - { - muduo::MutexLockGuard lock(mutex_); - if (buffers_.empty()) // unusual usage! - { - cond_.waitForSeconds(flushInterval_); - } - buffers_.push_back(std::move(currentBuffer_)); - currentBuffer_ = std::move(newBuffer1); - buffersToWrite.swap(buffers_); - if (!nextBuffer_) - { - nextBuffer_ = std::move(newBuffer2); - } - } - - assert(!buffersToWrite.empty()); - - if (buffersToWrite.size() > 25) - { - char buf[256]; - snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n", - Timestamp::now().toFormattedString().c_str(), - buffersToWrite.size()-2); - fputs(buf, stderr); - output.append(buf, static_cast(strlen(buf))); - buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end()); - } - - for (const auto& buffer : buffersToWrite) - { - // FIXME: use unbuffered stdio FILE ? or use ::writev ? - output.append(buffer->data(), buffer->length()); - } - - if (buffersToWrite.size() > 2) - { - // drop non-bzero-ed buffers, avoid trashing - buffersToWrite.resize(2); - } - - if (!newBuffer1) - { - assert(!buffersToWrite.empty()); - newBuffer1 = std::move(buffersToWrite.back()); - buffersToWrite.pop_back(); - newBuffer1->reset(); - } - - if (!newBuffer2) - { - assert(!buffersToWrite.empty()); - newBuffer2 = std::move(buffersToWrite.back()); - buffersToWrite.pop_back(); - newBuffer2->reset(); - } - - buffersToWrite.clear(); - output.flush(); - } - output.flush(); -} - diff --git a/include/muduo/base/AsyncLogging.h b/include/muduo/base/AsyncLogging.h deleted file mode 100644 index 46e77dd..0000000 --- a/include/muduo/base/AsyncLogging.h +++ /dev/null @@ -1,77 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_ASYNCLOGGING_H -#define MUDUO_BASE_ASYNCLOGGING_H - -#include "muduo/base/BlockingQueue.h" -#include "muduo/base/BoundedBlockingQueue.h" -#include "muduo/base/CountDownLatch.h" -#include "muduo/base/Mutex.h" -#include "muduo/base/Thread.h" -#include "muduo/base/LogStream.h" - -#include -#include - -namespace muduo -{ - -class AsyncLogging : noncopyable -{ - public: - - AsyncLogging(const string& basename, - off_t rollSize, - int flushInterval = 3); - - ~AsyncLogging() - { - if (running_) - { - stop(); - } - } - - void append(const char* logline, int len); - - void start() - { - running_ = true; - thread_.start(); - latch_.wait(); - } - - void stop() NO_THREAD_SAFETY_ANALYSIS - { - running_ = false; - cond_.notify(); - thread_.join(); - } - - private: - - void threadFunc(); - - typedef muduo::detail::FixedBuffer Buffer; - typedef std::vector> BufferVector; - typedef BufferVector::value_type BufferPtr; - - const int flushInterval_; - std::atomic running_; - const string basename_; - const off_t rollSize_; - muduo::Thread thread_; - muduo::CountDownLatch latch_; - muduo::MutexLock mutex_; - muduo::Condition cond_ GUARDED_BY(mutex_); - BufferPtr currentBuffer_ GUARDED_BY(mutex_); - BufferPtr nextBuffer_ GUARDED_BY(mutex_); - BufferVector buffers_ GUARDED_BY(mutex_); -}; - -} // namespace muduo - -#endif // MUDUO_BASE_ASYNCLOGGING_H diff --git a/include/muduo/base/Atomic.h b/include/muduo/base/Atomic.h deleted file mode 100644 index 6158fac..0000000 --- a/include/muduo/base/Atomic.h +++ /dev/null @@ -1,97 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_ATOMIC_H -#define MUDUO_BASE_ATOMIC_H - -#include "muduo/base/noncopyable.h" - -#include - -namespace muduo -{ - -namespace detail -{ -template -class AtomicIntegerT : noncopyable -{ - public: - AtomicIntegerT() - : value_(0) - { - } - - // uncomment if you need copying and assignment - // - // AtomicIntegerT(const AtomicIntegerT& that) - // : value_(that.get()) - // {} - // - // AtomicIntegerT& operator=(const AtomicIntegerT& that) - // { - // getAndSet(that.get()); - // return *this; - // } - - T get() - { - // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST) - return __sync_val_compare_and_swap(&value_, 0, 0); - } - - T getAndAdd(T x) - { - // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST) - return __sync_fetch_and_add(&value_, x); - } - - T addAndGet(T x) - { - return getAndAdd(x) + x; - } - - T incrementAndGet() - { - return addAndGet(1); - } - - T decrementAndGet() - { - return addAndGet(-1); - } - - void add(T x) - { - getAndAdd(x); - } - - void increment() - { - incrementAndGet(); - } - - void decrement() - { - decrementAndGet(); - } - - T getAndSet(T newValue) - { - // in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST) - return __sync_lock_test_and_set(&value_, newValue); - } - - private: - volatile T value_; -}; -} // namespace detail - -typedef detail::AtomicIntegerT AtomicInt32; -typedef detail::AtomicIntegerT AtomicInt64; - -} // namespace muduo - -#endif // MUDUO_BASE_ATOMIC_H diff --git a/include/muduo/base/BUILD.bazel b/include/muduo/base/BUILD.bazel deleted file mode 100644 index 48b598f..0000000 --- a/include/muduo/base/BUILD.bazel +++ /dev/null @@ -1,23 +0,0 @@ -cc_library( - name = "base", - srcs = [ - "AsyncLogging.cc", - "Condition.cc", - "CountDownLatch.cc", - "CurrentThread.cc", - "Date.cc", - "Exception.cc", - "FileUtil.cc", - "LogFile.cc", - "LogStream.cc", - "Logging.cc", - "ProcessInfo.cc", - "Thread.cc", - "ThreadPool.cc", - "TimeZone.cc", - "Timestamp.cc", - ], - hdrs = glob(["*.h"]), - linkopts = ["-pthread"], - visibility = ["//visibility:public"], -) diff --git a/include/muduo/base/BlockingQueue.h b/include/muduo/base/BlockingQueue.h deleted file mode 100644 index 407c012..0000000 --- a/include/muduo/base/BlockingQueue.h +++ /dev/null @@ -1,72 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_BLOCKINGQUEUE_H -#define MUDUO_BASE_BLOCKINGQUEUE_H - -#include "muduo/base/Condition.h" -#include "muduo/base/Mutex.h" - -#include -#include - -namespace muduo -{ - -template -class BlockingQueue : noncopyable -{ - public: - BlockingQueue() - : mutex_(), - notEmpty_(mutex_), - queue_() - { - } - - void put(const T& x) - { - MutexLockGuard lock(mutex_); - queue_.push_back(x); - notEmpty_.notify(); // wait morphing saves us - // http://www.domaigne.com/blog/computing/condvars-signal-with-mutex-locked-or-not/ - } - - void put(T&& x) - { - MutexLockGuard lock(mutex_); - queue_.push_back(std::move(x)); - notEmpty_.notify(); - } - - T take() - { - MutexLockGuard lock(mutex_); - // always use a while-loop, due to spurious wakeup - while (queue_.empty()) - { - notEmpty_.wait(); - } - assert(!queue_.empty()); - T front(std::move(queue_.front())); - queue_.pop_front(); - return front; - } - - size_t size() const - { - MutexLockGuard lock(mutex_); - return queue_.size(); - } - - private: - mutable MutexLock mutex_; - Condition notEmpty_ GUARDED_BY(mutex_); - std::deque queue_ GUARDED_BY(mutex_); -}; - -} // namespace muduo - -#endif // MUDUO_BASE_BLOCKINGQUEUE_H diff --git a/include/muduo/base/BoundedBlockingQueue.h b/include/muduo/base/BoundedBlockingQueue.h deleted file mode 100644 index cfb4d3b..0000000 --- a/include/muduo/base/BoundedBlockingQueue.h +++ /dev/null @@ -1,101 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H -#define MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H - -#include "muduo/base/Condition.h" -#include "muduo/base/Mutex.h" - -#include -#include - -namespace muduo -{ - -template -class BoundedBlockingQueue : noncopyable -{ - public: - explicit BoundedBlockingQueue(int maxSize) - : mutex_(), - notEmpty_(mutex_), - notFull_(mutex_), - queue_(maxSize) - { - } - - void put(const T& x) - { - MutexLockGuard lock(mutex_); - while (queue_.full()) - { - notFull_.wait(); - } - assert(!queue_.full()); - queue_.push_back(x); - notEmpty_.notify(); - } - - void put(T&& x) - { - MutexLockGuard lock(mutex_); - while (queue_.full()) - { - notFull_.wait(); - } - assert(!queue_.full()); - queue_.push_back(std::move(x)); - notEmpty_.notify(); - } - - T take() - { - MutexLockGuard lock(mutex_); - while (queue_.empty()) - { - notEmpty_.wait(); - } - assert(!queue_.empty()); - T front(std::move(queue_.front())); - queue_.pop_front(); - notFull_.notify(); - return front; - } - - bool empty() const - { - MutexLockGuard lock(mutex_); - return queue_.empty(); - } - - bool full() const - { - MutexLockGuard lock(mutex_); - return queue_.full(); - } - - size_t size() const - { - MutexLockGuard lock(mutex_); - return queue_.size(); - } - - size_t capacity() const - { - MutexLockGuard lock(mutex_); - return queue_.capacity(); - } - - private: - mutable MutexLock mutex_; - Condition notEmpty_ GUARDED_BY(mutex_); - Condition notFull_ GUARDED_BY(mutex_); - boost::circular_buffer queue_ GUARDED_BY(mutex_); -}; - -} // namespace muduo - -#endif // MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H diff --git a/include/muduo/base/CMakeLists.txt b/include/muduo/base/CMakeLists.txt deleted file mode 100644 index 96e2d02..0000000 --- a/include/muduo/base/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -set(base_SRCS - AsyncLogging.cc - Condition.cc - CountDownLatch.cc - CurrentThread.cc - Date.cc - Exception.cc - FileUtil.cc - LogFile.cc - Logging.cc - LogStream.cc - ProcessInfo.cc - Timestamp.cc - Thread.cc - ThreadPool.cc - TimeZone.cc - ) - -add_library(muduo_base ${base_SRCS}) -target_link_libraries(muduo_base pthread rt) - -#add_library(muduo_base_cpp11 ${base_SRCS}) -#target_link_libraries(muduo_base_cpp11 pthread rt) -#set_target_properties(muduo_base_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") - -install(TARGETS muduo_base DESTINATION lib) -#install(TARGETS muduo_base_cpp11 DESTINATION lib) - -file(GLOB HEADERS "*.h") -install(FILES ${HEADERS} DESTINATION include/muduo/base) - -if(MUDUO_BUILD_EXAMPLES) - add_subdirectory(tests) -endif() diff --git a/include/muduo/base/Condition.cc b/include/muduo/base/Condition.cc deleted file mode 100644 index 47e9d23..0000000 --- a/include/muduo/base/Condition.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/Condition.h" - -#include - -// returns true if time out, false otherwise. -bool muduo::Condition::waitForSeconds(double seconds) -{ - struct timespec abstime; - // FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind. - clock_gettime(CLOCK_REALTIME, &abstime); - - const int64_t kNanoSecondsPerSecond = 1000000000; - int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); - - abstime.tv_sec += static_cast((abstime.tv_nsec + nanoseconds) / kNanoSecondsPerSecond); - abstime.tv_nsec = static_cast((abstime.tv_nsec + nanoseconds) % kNanoSecondsPerSecond); - - MutexLock::UnassignGuard ug(mutex_); - return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime); -} - diff --git a/include/muduo/base/Condition.h b/include/muduo/base/Condition.h deleted file mode 100644 index 0181550..0000000 --- a/include/muduo/base/Condition.h +++ /dev/null @@ -1,56 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_CONDITION_H -#define MUDUO_BASE_CONDITION_H - -#include "muduo/base/Mutex.h" - -#include - -namespace muduo -{ - -class Condition : noncopyable -{ - public: - explicit Condition(MutexLock& mutex) - : mutex_(mutex) - { - MCHECK(pthread_cond_init(&pcond_, NULL)); - } - - ~Condition() - { - MCHECK(pthread_cond_destroy(&pcond_)); - } - - void wait() - { - MutexLock::UnassignGuard ug(mutex_); - MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex())); - } - - // returns true if time out, false otherwise. - bool waitForSeconds(double seconds); - - void notify() - { - MCHECK(pthread_cond_signal(&pcond_)); - } - - void notifyAll() - { - MCHECK(pthread_cond_broadcast(&pcond_)); - } - - private: - MutexLock& mutex_; - pthread_cond_t pcond_; -}; - -} // namespace muduo - -#endif // MUDUO_BASE_CONDITION_H diff --git a/include/muduo/base/CountDownLatch.cc b/include/muduo/base/CountDownLatch.cc deleted file mode 100644 index 72d26cc..0000000 --- a/include/muduo/base/CountDownLatch.cc +++ /dev/null @@ -1,41 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/CountDownLatch.h" - -using namespace muduo; - -CountDownLatch::CountDownLatch(int count) - : mutex_(), - condition_(mutex_), - count_(count) -{ -} - -void CountDownLatch::wait() -{ - MutexLockGuard lock(mutex_); - while (count_ > 0) - { - condition_.wait(); - } -} - -void CountDownLatch::countDown() -{ - MutexLockGuard lock(mutex_); - --count_; - if (count_ == 0) - { - condition_.notifyAll(); - } -} - -int CountDownLatch::getCount() const -{ - MutexLockGuard lock(mutex_); - return count_; -} - diff --git a/include/muduo/base/CountDownLatch.h b/include/muduo/base/CountDownLatch.h deleted file mode 100644 index 9919aef..0000000 --- a/include/muduo/base/CountDownLatch.h +++ /dev/null @@ -1,34 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_COUNTDOWNLATCH_H -#define MUDUO_BASE_COUNTDOWNLATCH_H - -#include "muduo/base/Condition.h" -#include "muduo/base/Mutex.h" - -namespace muduo -{ - -class CountDownLatch : noncopyable -{ - public: - - explicit CountDownLatch(int count); - - void wait(); - - void countDown(); - - int getCount() const; - - private: - mutable MutexLock mutex_; - Condition condition_ GUARDED_BY(mutex_); - int count_ GUARDED_BY(mutex_); -}; - -} // namespace muduo -#endif // MUDUO_BASE_COUNTDOWNLATCH_H diff --git a/include/muduo/base/CurrentThread.cc b/include/muduo/base/CurrentThread.cc deleted file mode 100644 index 15edff0..0000000 --- a/include/muduo/base/CurrentThread.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/CurrentThread.h" - -#include -#include -#include - -namespace muduo -{ -namespace CurrentThread -{ -__thread int t_cachedTid = 0; -__thread char t_tidString[32]; -__thread int t_tidStringLength = 6; -__thread const char* t_threadName = "unknown"; -static_assert(std::is_same::value, "pid_t should be int"); - -string stackTrace(bool demangle) -{ - string stack; - const int max_frames = 200; - void* frame[max_frames]; - int nptrs = ::backtrace(frame, max_frames); - char** strings = ::backtrace_symbols(frame, nptrs); - if (strings) - { - size_t len = 256; - char* demangled = demangle ? static_cast(::malloc(len)) : nullptr; - for (int i = 1; i < nptrs; ++i) // skipping the 0-th, which is this function - { - if (demangle) - { - // https://panthema.net/2008/0901-stacktrace-demangled/ - // bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909] - char* left_par = nullptr; - char* plus = nullptr; - for (char* p = strings[i]; *p; ++p) - { - if (*p == '(') - left_par = p; - else if (*p == '+') - plus = p; - } - - if (left_par && plus) - { - *plus = '\0'; - int status = 0; - char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status); - *plus = '+'; - if (status == 0) - { - demangled = ret; // ret could be realloc() - stack.append(strings[i], left_par+1); - stack.append(demangled); - stack.append(plus); - stack.push_back('\n'); - continue; - } - } - } - // Fallback to mangled names - stack.append(strings[i]); - stack.push_back('\n'); - } - free(demangled); - free(strings); - } - return stack; -} - -} // namespace CurrentThread -} // namespace muduo diff --git a/include/muduo/base/CurrentThread.h b/include/muduo/base/CurrentThread.h deleted file mode 100644 index 33fd8c0..0000000 --- a/include/muduo/base/CurrentThread.h +++ /dev/null @@ -1,54 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_CURRENTTHREAD_H -#define MUDUO_BASE_CURRENTTHREAD_H - -#include "muduo/base/Types.h" - -namespace muduo -{ -namespace CurrentThread -{ - // internal - extern __thread int t_cachedTid; - extern __thread char t_tidString[32]; - extern __thread int t_tidStringLength; - extern __thread const char* t_threadName; - void cacheTid(); - - inline int tid() - { - if (__builtin_expect(t_cachedTid == 0, 0)) - { - cacheTid(); - } - return t_cachedTid; - } - - inline const char* tidString() // for logging - { - return t_tidString; - } - - inline int tidStringLength() // for logging - { - return t_tidStringLength; - } - - inline const char* name() - { - return t_threadName; - } - - bool isMainThread(); - - void sleepUsec(int64_t usec); // for testing - - string stackTrace(bool demangle); -} // namespace CurrentThread -} // namespace muduo - -#endif // MUDUO_BASE_CURRENTTHREAD_H diff --git a/include/muduo/base/Date.cc b/include/muduo/base/Date.cc deleted file mode 100644 index 86b6071..0000000 --- a/include/muduo/base/Date.cc +++ /dev/null @@ -1,76 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/Date.h" -#include // snprintf -#include // struct tm - -namespace muduo -{ -namespace detail -{ - -char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; - -// algorithm and explanation see: -// http://www.faqs.org/faqs/calendars/faq/part2/ -// http://blog.csdn.net/Solstice - -int getJulianDayNumber(int year, int month, int day) -{ - (void) require_32_bit_integer_at_least; // no warning please - int a = (14 - month) / 12; - int y = year + 4800 - a; - int m = month + 12 * a - 3; - return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; -} - -struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) -{ - int a = julianDayNumber + 32044; - int b = (4 * a + 3) / 146097; - int c = a - ((b * 146097) / 4); - int d = (4 * c + 3) / 1461; - int e = c - ((1461 * d) / 4); - int m = (5 * e + 2) / 153; - Date::YearMonthDay ymd; - ymd.day = e - ((153 * m + 2) / 5) + 1; - ymd.month = m + 3 - 12 * (m / 10); - ymd.year = b * 100 + d - 4800 + (m / 10); - return ymd; -} -} // namespace detail -const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1); -} // namespace muduo - -using namespace muduo; -using namespace muduo::detail; - -Date::Date(int y, int m, int d) - : julianDayNumber_(getJulianDayNumber(y, m, d)) -{ -} - -Date::Date(const struct tm& t) - : julianDayNumber_(getJulianDayNumber( - t.tm_year+1900, - t.tm_mon+1, - t.tm_mday)) -{ -} - -string Date::toIsoString() const -{ - char buf[32]; - YearMonthDay ymd(yearMonthDay()); - snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); - return buf; -} - -Date::YearMonthDay Date::yearMonthDay() const -{ - return getYearMonthDay(julianDayNumber_); -} - diff --git a/include/muduo/base/Date.h b/include/muduo/base/Date.h deleted file mode 100644 index 2e27b19..0000000 --- a/include/muduo/base/Date.h +++ /dev/null @@ -1,119 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_DATE_H -#define MUDUO_BASE_DATE_H - -#include "muduo/base/copyable.h" -#include "muduo/base/Types.h" - -struct tm; - -namespace muduo -{ - -/// -/// Date in Gregorian calendar. -/// -/// This class is immutable. -/// It's recommended to pass it by value, since it's passed in register on x64. -/// -class Date : public muduo::copyable - // public boost::less_than_comparable, - // public boost::equality_comparable -{ - public: - - struct YearMonthDay - { - int year; // [1900..2500] - int month; // [1..12] - int day; // [1..31] - }; - - static const int kDaysPerWeek = 7; - static const int kJulianDayOf1970_01_01; - - /// - /// Constucts an invalid Date. - /// - Date() - : julianDayNumber_(0) - {} - - /// - /// Constucts a yyyy-mm-dd Date. - /// - /// 1 <= month <= 12 - Date(int year, int month, int day); - - /// - /// Constucts a Date from Julian Day Number. - /// - explicit Date(int julianDayNum) - : julianDayNumber_(julianDayNum) - {} - - /// - /// Constucts a Date from struct tm - /// - explicit Date(const struct tm&); - - // default copy/assignment/dtor are Okay - - void swap(Date& that) - { - std::swap(julianDayNumber_, that.julianDayNumber_); - } - - bool valid() const { return julianDayNumber_ > 0; } - - /// - /// Converts to yyyy-mm-dd format. - /// - string toIsoString() const; - - struct YearMonthDay yearMonthDay() const; - - int year() const - { - return yearMonthDay().year; - } - - int month() const - { - return yearMonthDay().month; - } - - int day() const - { - return yearMonthDay().day; - } - - // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ] - int weekDay() const - { - return (julianDayNumber_+1) % kDaysPerWeek; - } - - int julianDayNumber() const { return julianDayNumber_; } - - private: - int julianDayNumber_; -}; - -inline bool operator<(Date x, Date y) -{ - return x.julianDayNumber() < y.julianDayNumber(); -} - -inline bool operator==(Date x, Date y) -{ - return x.julianDayNumber() == y.julianDayNumber(); -} - -} // namespace muduo - -#endif // MUDUO_BASE_DATE_H diff --git a/include/muduo/base/Exception.cc b/include/muduo/base/Exception.cc deleted file mode 100644 index 6e2afbe..0000000 --- a/include/muduo/base/Exception.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/Exception.h" -#include "muduo/base/CurrentThread.h" - -namespace muduo -{ - -Exception::Exception(string msg) - : message_(std::move(msg)), - stack_(CurrentThread::stackTrace(/*demangle=*/false)) -{ -} - -} // namespace muduo diff --git a/include/muduo/base/Exception.h b/include/muduo/base/Exception.h deleted file mode 100644 index 2a74622..0000000 --- a/include/muduo/base/Exception.h +++ /dev/null @@ -1,40 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_EXCEPTION_H -#define MUDUO_BASE_EXCEPTION_H - -#include "muduo/base/Types.h" -#include - -namespace muduo -{ - -class Exception : public std::exception -{ - public: - Exception(string what); - ~Exception() noexcept override = default; - - // default copy-ctor and operator= are okay. - - const char* what() const noexcept override - { - return message_.c_str(); - } - - const char* stackTrace() const noexcept - { - return stack_.c_str(); - } - - private: - string message_; - string stack_; -}; - -} // namespace muduo - -#endif // MUDUO_BASE_EXCEPTION_H diff --git a/include/muduo/base/FileUtil.cc b/include/muduo/base/FileUtil.cc deleted file mode 100644 index 2a73886..0000000 --- a/include/muduo/base/FileUtil.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/FileUtil.h" -#include "muduo/base/Logging.h" - -#include -#include -#include -#include -#include -#include - -using namespace muduo; - -FileUtil::AppendFile::AppendFile(StringArg filename) - : fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC - writtenBytes_(0) -{ - assert(fp_); - ::setbuffer(fp_, buffer_, sizeof buffer_); - // posix_fadvise POSIX_FADV_DONTNEED ? -} - -FileUtil::AppendFile::~AppendFile() -{ - ::fclose(fp_); -} - -void FileUtil::AppendFile::append(const char* logline, const size_t len) -{ - size_t n = write(logline, len); - size_t remain = len - n; - while (remain > 0) - { - size_t x = write(logline + n, remain); - if (x == 0) - { - int err = ferror(fp_); - if (err) - { - fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err)); - } - break; - } - n += x; - remain = len - n; // remain -= x - } - - writtenBytes_ += len; -} - -void FileUtil::AppendFile::flush() -{ - ::fflush(fp_); -} - -size_t FileUtil::AppendFile::write(const char* logline, size_t len) -{ - // #undef fwrite_unlocked - return ::fwrite_unlocked(logline, 1, len, fp_); -} - -FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename) - : fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), - err_(0) -{ - buf_[0] = '\0'; - if (fd_ < 0) - { - err_ = errno; - } -} - -FileUtil::ReadSmallFile::~ReadSmallFile() -{ - if (fd_ >= 0) - { - ::close(fd_); // FIXME: check EINTR - } -} - -// return errno -template -int FileUtil::ReadSmallFile::readToString(int maxSize, - String* content, - int64_t* fileSize, - int64_t* modifyTime, - int64_t* createTime) -{ - static_assert(sizeof(off_t) == 8, "_FILE_OFFSET_BITS = 64"); - assert(content != NULL); - int err = err_; - if (fd_ >= 0) - { - content->clear(); - - if (fileSize) - { - struct stat statbuf; - if (::fstat(fd_, &statbuf) == 0) - { - if (S_ISREG(statbuf.st_mode)) - { - *fileSize = statbuf.st_size; - content->reserve(static_cast(std::min(implicit_cast(maxSize), *fileSize))); - } - else if (S_ISDIR(statbuf.st_mode)) - { - err = EISDIR; - } - if (modifyTime) - { - *modifyTime = statbuf.st_mtime; - } - if (createTime) - { - *createTime = statbuf.st_ctime; - } - } - else - { - err = errno; - } - } - - while (content->size() < implicit_cast(maxSize)) - { - size_t toRead = std::min(implicit_cast(maxSize) - content->size(), sizeof(buf_)); - ssize_t n = ::read(fd_, buf_, toRead); - if (n > 0) - { - content->append(buf_, n); - } - else - { - if (n < 0) - { - err = errno; - } - break; - } - } - } - return err; -} - -int FileUtil::ReadSmallFile::readToBuffer(int* size) -{ - int err = err_; - if (fd_ >= 0) - { - ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0); - if (n >= 0) - { - if (size) - { - *size = static_cast(n); - } - buf_[n] = '\0'; - } - else - { - err = errno; - } - } - return err; -} - -template int FileUtil::readFile(StringArg filename, - int maxSize, - string* content, - int64_t*, int64_t*, int64_t*); - -template int FileUtil::ReadSmallFile::readToString( - int maxSize, - string* content, - int64_t*, int64_t*, int64_t*); - diff --git a/include/muduo/base/FileUtil.h b/include/muduo/base/FileUtil.h deleted file mode 100644 index 62ddebc..0000000 --- a/include/muduo/base/FileUtil.h +++ /dev/null @@ -1,89 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_BASE_FILEUTIL_H -#define MUDUO_BASE_FILEUTIL_H - -#include "muduo/base/noncopyable.h" -#include "muduo/base/StringPiece.h" -#include // for off_t - -namespace muduo -{ -namespace FileUtil -{ - -// read small file < 64KB -class ReadSmallFile : noncopyable -{ - public: - ReadSmallFile(StringArg filename); - ~ReadSmallFile(); - - // return errno - template - int readToString(int maxSize, - String* content, - int64_t* fileSize, - int64_t* modifyTime, - int64_t* createTime); - - /// Read at maxium kBufferSize into buf_ - // return errno - int readToBuffer(int* size); - - const char* buffer() const { return buf_; } - - static const int kBufferSize = 64*1024; - - private: - int fd_; - int err_; - char buf_[kBufferSize]; -}; - -// read the file content, returns errno if error happens. -template -int readFile(StringArg filename, - int maxSize, - String* content, - int64_t* fileSize = NULL, - int64_t* modifyTime = NULL, - int64_t* createTime = NULL) -{ - ReadSmallFile file(filename); - return file.readToString(maxSize, content, fileSize, modifyTime, createTime); -} - -// not thread safe -class AppendFile : noncopyable -{ - public: - explicit AppendFile(StringArg filename); - - ~AppendFile(); - - void append(const char* logline, size_t len); - - void flush(); - - off_t writtenBytes() const { return writtenBytes_; } - - private: - - size_t write(const char* logline, size_t len); - - FILE* fp_; - char buffer_[64*1024]; - off_t writtenBytes_; -}; - -} // namespace FileUtil -} // namespace muduo - -#endif // MUDUO_BASE_FILEUTIL_H - diff --git a/include/muduo/base/GzipFile.h b/include/muduo/base/GzipFile.h deleted file mode 100644 index 68a538c..0000000 --- a/include/muduo/base/GzipFile.h +++ /dev/null @@ -1,89 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#pragma once - -#include "muduo/base/StringPiece.h" -#include "muduo/base/noncopyable.h" -#include - -namespace muduo -{ - -class GzipFile : noncopyable -{ - public: - GzipFile(GzipFile&& rhs) noexcept - : file_(rhs.file_) - { - rhs.file_ = NULL; - } - - ~GzipFile() - { - if (file_) - { - ::gzclose(file_); - } - } - - GzipFile& operator=(GzipFile&& rhs) noexcept - { - swap(rhs); - return *this; - } - - bool valid() const { return file_ != NULL; } - void swap(GzipFile& rhs) { std::swap(file_, rhs.file_); } -#if ZLIB_VERNUM >= 0x1240 - bool setBuffer(int size) { return ::gzbuffer(file_, size) == 0; } -#endif - - // return the number of uncompressed bytes actually read, 0 for eof, -1 for error - int read(void* buf, int len) { return ::gzread(file_, buf, len); } - - // return the number of uncompressed bytes actually written - int write(StringPiece buf) { return ::gzwrite(file_, buf.data(), buf.size()); } - - // number of uncompressed bytes - off_t tell() const { return ::gztell(file_); } - -#if ZLIB_VERNUM >= 0x1240 - // number of compressed bytes - off_t offset() const { return ::gzoffset(file_); } -#endif - - // int flush(int f) { return ::gzflush(file_, f); } - - static GzipFile openForRead(StringArg filename) - { - return GzipFile(::gzopen(filename.c_str(), "rbe")); - } - - static GzipFile openForAppend(StringArg filename) - { - return GzipFile(::gzopen(filename.c_str(), "abe")); - } - - static GzipFile openForWriteExclusive(StringArg filename) - { - return GzipFile(::gzopen(filename.c_str(), "wbxe")); - } - - static GzipFile openForWriteTruncate(StringArg filename) - { - return GzipFile(::gzopen(filename.c_str(), "wbe")); - } - - private: - explicit GzipFile(gzFile file) - : file_(file) - { - } - - gzFile file_; -}; - -} // namespace muduo diff --git a/include/muduo/base/LogFile.cc b/include/muduo/base/LogFile.cc deleted file mode 100644 index 2a12abe..0000000 --- a/include/muduo/base/LogFile.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/LogFile.h" - -#include "muduo/base/FileUtil.h" -#include "muduo/base/ProcessInfo.h" - -#include -#include -#include - -using namespace muduo; - -LogFile::LogFile(const string& basename, - off_t rollSize, - bool threadSafe, - int flushInterval, - int checkEveryN) - : basename_(basename), - rollSize_(rollSize), - flushInterval_(flushInterval), - checkEveryN_(checkEveryN), - count_(0), - mutex_(threadSafe ? new MutexLock : NULL), - startOfPeriod_(0), - lastRoll_(0), - lastFlush_(0) -{ - assert(basename.find('/') == string::npos); - rollFile(); -} - -LogFile::~LogFile() = default; - -void LogFile::append(const char* logline, int len) -{ - if (mutex_) - { - MutexLockGuard lock(*mutex_); - append_unlocked(logline, len); - } - else - { - append_unlocked(logline, len); - } -} - -void LogFile::flush() -{ - if (mutex_) - { - MutexLockGuard lock(*mutex_); - file_->flush(); - } - else - { - file_->flush(); - } -} - -void LogFile::append_unlocked(const char* logline, int len) -{ - file_->append(logline, len); - - if (file_->writtenBytes() > rollSize_) - { - rollFile(); - } - else - { - ++count_; - if (count_ >= checkEveryN_) - { - count_ = 0; - time_t now = ::time(NULL); - time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_; - if (thisPeriod_ != startOfPeriod_) - { - rollFile(); - } - else if (now - lastFlush_ > flushInterval_) - { - lastFlush_ = now; - file_->flush(); - } - } - } -} - -bool LogFile::rollFile() -{ - time_t now = 0; - string filename = getLogFileName(basename_, &now); - time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; - - if (now > lastRoll_) - { - lastRoll_ = now; - lastFlush_ = now; - startOfPeriod_ = start; - file_.reset(new FileUtil::AppendFile(filename)); - return true; - } - return false; -} - -string LogFile::getLogFileName(const string& basename, time_t* now) -{ - string filename; - filename.reserve(basename.size() + 64); - filename = basename; - - char timebuf[32]; - struct tm tm; - *now = time(NULL); - gmtime_r(now, &tm); // FIXME: localtime_r ? - strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm); - filename += timebuf; - - filename += ProcessInfo::hostname(); - - char pidbuf[32]; - snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); - filename += pidbuf; - - filename += ".log"; - - return filename; -} - diff --git a/include/muduo/base/LogFile.h b/include/muduo/base/LogFile.h deleted file mode 100644 index 7abd583..0000000 --- a/include/muduo/base/LogFile.h +++ /dev/null @@ -1,58 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_LOGFILE_H -#define MUDUO_BASE_LOGFILE_H - -#include "muduo/base/Mutex.h" -#include "muduo/base/Types.h" - -#include - -namespace muduo -{ - -namespace FileUtil -{ -class AppendFile; -} - -class LogFile : noncopyable -{ - public: - LogFile(const string& basename, - off_t rollSize, - bool threadSafe = true, - int flushInterval = 3, - int checkEveryN = 1024); - ~LogFile(); - - void append(const char* logline, int len); - void flush(); - bool rollFile(); - - private: - void append_unlocked(const char* logline, int len); - - static string getLogFileName(const string& basename, time_t* now); - - const string basename_; - const off_t rollSize_; - const int flushInterval_; - const int checkEveryN_; - - int count_; - - std::unique_ptr mutex_; - time_t startOfPeriod_; - time_t lastRoll_; - time_t lastFlush_; - std::unique_ptr file_; - - const static int kRollPerSeconds_ = 60*60*24; -}; - -} // namespace muduo -#endif // MUDUO_BASE_LOGFILE_H diff --git a/include/muduo/base/LogStream.cc b/include/muduo/base/LogStream.cc deleted file mode 100644 index cafd5b8..0000000 --- a/include/muduo/base/LogStream.cc +++ /dev/null @@ -1,342 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/LogStream.h" - -#include -#include -#include -#include -#include -#include -#include - -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif - -#include - - -using namespace muduo; -using namespace muduo::detail; - -// TODO: better itoa. -#if defined(__clang__) -#pragma clang diagnostic ignored "-Wtautological-compare" -#else -#pragma GCC diagnostic ignored "-Wtype-limits" -#endif - -namespace muduo -{ -namespace detail -{ - -const char digits[] = "9876543210123456789"; -const char* zero = digits + 9; -static_assert(sizeof(digits) == 20, "wrong number of digits"); - -const char digitsHex[] = "0123456789ABCDEF"; -static_assert(sizeof digitsHex == 17, "wrong number of digitsHex"); - -// Efficient Integer to String Conversions, by Matthew Wilson. -template -size_t convert(char buf[], T value) -{ - T i = value; - char* p = buf; - - do - { - int lsd = static_cast(i % 10); - i /= 10; - *p++ = zero[lsd]; - } while (i != 0); - - if (value < 0) - { - *p++ = '-'; - } - *p = '\0'; - std::reverse(buf, p); - - return p - buf; -} - -size_t convertHex(char buf[], uintptr_t value) -{ - uintptr_t i = value; - char* p = buf; - - do - { - int lsd = static_cast(i % 16); - i /= 16; - *p++ = digitsHex[lsd]; - } while (i != 0); - - *p = '\0'; - std::reverse(buf, p); - - return p - buf; -} - -template class FixedBuffer; -template class FixedBuffer; - -} // namespace detail - -/* - Format a number with 5 characters, including SI units. - [0, 999] - [1.00k, 999k] - [1.00M, 999M] - [1.00G, 999G] - [1.00T, 999T] - [1.00P, 999P] - [1.00E, inf) -*/ -std::string formatSI(int64_t s) -{ - double n = static_cast(s); - char buf[64]; - if (s < 1000) - snprintf(buf, sizeof(buf), "%" PRId64, s); - else if (s < 9995) - snprintf(buf, sizeof(buf), "%.2fk", n/1e3); - else if (s < 99950) - snprintf(buf, sizeof(buf), "%.1fk", n/1e3); - else if (s < 999500) - snprintf(buf, sizeof(buf), "%.0fk", n/1e3); - else if (s < 9995000) - snprintf(buf, sizeof(buf), "%.2fM", n/1e6); - else if (s < 99950000) - snprintf(buf, sizeof(buf), "%.1fM", n/1e6); - else if (s < 999500000) - snprintf(buf, sizeof(buf), "%.0fM", n/1e6); - else if (s < 9995000000) - snprintf(buf, sizeof(buf), "%.2fG", n/1e9); - else if (s < 99950000000) - snprintf(buf, sizeof(buf), "%.1fG", n/1e9); - else if (s < 999500000000) - snprintf(buf, sizeof(buf), "%.0fG", n/1e9); - else if (s < 9995000000000) - snprintf(buf, sizeof(buf), "%.2fT", n/1e12); - else if (s < 99950000000000) - snprintf(buf, sizeof(buf), "%.1fT", n/1e12); - else if (s < 999500000000000) - snprintf(buf, sizeof(buf), "%.0fT", n/1e12); - else if (s < 9995000000000000) - snprintf(buf, sizeof(buf), "%.2fP", n/1e15); - else if (s < 99950000000000000) - snprintf(buf, sizeof(buf), "%.1fP", n/1e15); - else if (s < 999500000000000000) - snprintf(buf, sizeof(buf), "%.0fP", n/1e15); - else - snprintf(buf, sizeof(buf), "%.2fE", n/1e18); - return buf; -} - -/* - [0, 1023] - [1.00Ki, 9.99Ki] - [10.0Ki, 99.9Ki] - [ 100Ki, 1023Ki] - [1.00Mi, 9.99Mi] -*/ -std::string formatIEC(int64_t s) -{ - double n = static_cast(s); - char buf[64]; - const double Ki = 1024.0; - const double Mi = Ki * 1024.0; - const double Gi = Mi * 1024.0; - const double Ti = Gi * 1024.0; - const double Pi = Ti * 1024.0; - const double Ei = Pi * 1024.0; - - if (n < Ki) - snprintf(buf, sizeof buf, "%" PRId64, s); - else if (n < Ki*9.995) - snprintf(buf, sizeof buf, "%.2fKi", n / Ki); - else if (n < Ki*99.95) - snprintf(buf, sizeof buf, "%.1fKi", n / Ki); - else if (n < Ki*1023.5) - snprintf(buf, sizeof buf, "%.0fKi", n / Ki); - - else if (n < Mi*9.995) - snprintf(buf, sizeof buf, "%.2fMi", n / Mi); - else if (n < Mi*99.95) - snprintf(buf, sizeof buf, "%.1fMi", n / Mi); - else if (n < Mi*1023.5) - snprintf(buf, sizeof buf, "%.0fMi", n / Mi); - - else if (n < Gi*9.995) - snprintf(buf, sizeof buf, "%.2fGi", n / Gi); - else if (n < Gi*99.95) - snprintf(buf, sizeof buf, "%.1fGi", n / Gi); - else if (n < Gi*1023.5) - snprintf(buf, sizeof buf, "%.0fGi", n / Gi); - - else if (n < Ti*9.995) - snprintf(buf, sizeof buf, "%.2fTi", n / Ti); - else if (n < Ti*99.95) - snprintf(buf, sizeof buf, "%.1fTi", n / Ti); - else if (n < Ti*1023.5) - snprintf(buf, sizeof buf, "%.0fTi", n / Ti); - - else if (n < Pi*9.995) - snprintf(buf, sizeof buf, "%.2fPi", n / Pi); - else if (n < Pi*99.95) - snprintf(buf, sizeof buf, "%.1fPi", n / Pi); - else if (n < Pi*1023.5) - snprintf(buf, sizeof buf, "%.0fPi", n / Pi); - - else if (n < Ei*9.995) - snprintf(buf, sizeof buf, "%.2fEi", n / Ei ); - else - snprintf(buf, sizeof buf, "%.1fEi", n / Ei ); - return buf; -} - -} // namespace muduo - -template -const char* FixedBuffer::debugString() -{ - *cur_ = '\0'; - return data_; -} - -template -void FixedBuffer::cookieStart() -{ -} - -template -void FixedBuffer::cookieEnd() -{ -} - -void LogStream::staticCheck() -{ - static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, - "kMaxNumericSize is large enough"); - static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, - "kMaxNumericSize is large enough"); - static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, - "kMaxNumericSize is large enough"); - static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, - "kMaxNumericSize is large enough"); -} - -template -void LogStream::formatInteger(T v) -{ - if (buffer_.avail() >= kMaxNumericSize) - { - size_t len = convert(buffer_.current(), v); - buffer_.add(len); - } -} - -LogStream& LogStream::operator<<(short v) -{ - *this << static_cast(v); - return *this; -} - -LogStream& LogStream::operator<<(unsigned short v) -{ - *this << static_cast(v); - return *this; -} - -LogStream& LogStream::operator<<(int v) -{ - formatInteger(v); - return *this; -} - -LogStream& LogStream::operator<<(unsigned int v) -{ - formatInteger(v); - return *this; -} - -LogStream& LogStream::operator<<(long v) -{ - formatInteger(v); - return *this; -} - -LogStream& LogStream::operator<<(unsigned long v) -{ - formatInteger(v); - return *this; -} - -LogStream& LogStream::operator<<(long long v) -{ - formatInteger(v); - return *this; -} - -LogStream& LogStream::operator<<(unsigned long long v) -{ - formatInteger(v); - return *this; -} - -LogStream& LogStream::operator<<(const void* p) -{ - uintptr_t v = reinterpret_cast(p); - if (buffer_.avail() >= kMaxNumericSize) - { - char* buf = buffer_.current(); - buf[0] = '0'; - buf[1] = 'x'; - size_t len = convertHex(buf+2, v); - buffer_.add(len+2); - } - return *this; -} - -// FIXME: replace this with Grisu3 by Florian Loitsch. -LogStream& LogStream::operator<<(double v) -{ - if (buffer_.avail() >= kMaxNumericSize) - { - int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v); - buffer_.add(len); - } - return *this; -} - -template -Fmt::Fmt(const char* fmt, T val) -{ - static_assert(std::is_arithmetic::value == true, "Must be arithmetic type"); - - length_ = snprintf(buf_, sizeof buf_, fmt, val); - assert(static_cast(length_) < sizeof buf_); -} - -// Explicit instantiations - -template Fmt::Fmt(const char* fmt, char); - -template Fmt::Fmt(const char* fmt, short); -template Fmt::Fmt(const char* fmt, unsigned short); -template Fmt::Fmt(const char* fmt, int); -template Fmt::Fmt(const char* fmt, unsigned int); -template Fmt::Fmt(const char* fmt, long); -template Fmt::Fmt(const char* fmt, unsigned long); -template Fmt::Fmt(const char* fmt, long long); -template Fmt::Fmt(const char* fmt, unsigned long long); - -template Fmt::Fmt(const char* fmt, float); -template Fmt::Fmt(const char* fmt, double); diff --git a/include/muduo/base/LogStream.h b/include/muduo/base/LogStream.h deleted file mode 100644 index a28eb46..0000000 --- a/include/muduo/base/LogStream.h +++ /dev/null @@ -1,203 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_LOGSTREAM_H -#define MUDUO_BASE_LOGSTREAM_H - -#include "muduo/base/noncopyable.h" -#include "muduo/base/StringPiece.h" -#include "muduo/base/Types.h" -#include -#include // memcpy - -namespace muduo -{ - -namespace detail -{ - -const int kSmallBuffer = 4000; -const int kLargeBuffer = 4000*1000; - -template -class FixedBuffer : noncopyable -{ - public: - FixedBuffer() - : cur_(data_) - { - setCookie(cookieStart); - } - - ~FixedBuffer() - { - setCookie(cookieEnd); - } - - void append(const char* /*restrict*/ buf, size_t len) - { - // FIXME: append partially - if (implicit_cast(avail()) > len) - { - memcpy(cur_, buf, len); - cur_ += len; - } - } - - const char* data() const { return data_; } - int length() const { return static_cast(cur_ - data_); } - - // write to data_ directly - char* current() { return cur_; } - int avail() const { return static_cast(end() - cur_); } - void add(size_t len) { cur_ += len; } - - void reset() { cur_ = data_; } - void bzero() { memZero(data_, sizeof data_); } - - // for used by GDB - const char* debugString(); - void setCookie(void (*cookie)()) { cookie_ = cookie; } - // for used by unit test - string toString() const { return string(data_, length()); } - StringPiece toStringPiece() const { return StringPiece(data_, length()); } - - private: - const char* end() const { return data_ + sizeof data_; } - // Must be outline function for cookies. - static void cookieStart(); - static void cookieEnd(); - - void (*cookie_)(); - char data_[SIZE]; - char* cur_; -}; - -} // namespace detail - -class LogStream : noncopyable -{ - typedef LogStream self; - public: - typedef detail::FixedBuffer Buffer; - - self& operator<<(bool v) - { - buffer_.append(v ? "1" : "0", 1); - return *this; - } - - self& operator<<(short); - self& operator<<(unsigned short); - self& operator<<(int); - self& operator<<(unsigned int); - self& operator<<(long); - self& operator<<(unsigned long); - self& operator<<(long long); - self& operator<<(unsigned long long); - - self& operator<<(const void*); - - self& operator<<(float v) - { - *this << static_cast(v); - return *this; - } - self& operator<<(double); - // self& operator<<(long double); - - self& operator<<(char v) - { - buffer_.append(&v, 1); - return *this; - } - - // self& operator<<(signed char); - // self& operator<<(unsigned char); - - self& operator<<(const char* str) - { - if (str) - { - buffer_.append(str, strlen(str)); - } - else - { - buffer_.append("(null)", 6); - } - return *this; - } - - self& operator<<(const unsigned char* str) - { - return operator<<(reinterpret_cast(str)); - } - - self& operator<<(const string& v) - { - buffer_.append(v.c_str(), v.size()); - return *this; - } - - self& operator<<(const StringPiece& v) - { - buffer_.append(v.data(), v.size()); - return *this; - } - - self& operator<<(const Buffer& v) - { - *this << v.toStringPiece(); - return *this; - } - - void append(const char* data, int len) { buffer_.append(data, len); } - const Buffer& buffer() const { return buffer_; } - void resetBuffer() { buffer_.reset(); } - - private: - void staticCheck(); - - template - void formatInteger(T); - - Buffer buffer_; - - static const int kMaxNumericSize = 32; -}; - -class Fmt // : noncopyable -{ - public: - template - Fmt(const char* fmt, T val); - - const char* data() const { return buf_; } - int length() const { return length_; } - - private: - char buf_[32]; - int length_; -}; - -inline LogStream& operator<<(LogStream& s, const Fmt& fmt) -{ - s.append(fmt.data(), fmt.length()); - return s; -} - -// Format quantity n in SI units (k, M, G, T, P, E). -// The returned string is atmost 5 characters long. -// Requires n >= 0 -string formatSI(int64_t n); - -// Format quantity n in IEC (binary) units (Ki, Mi, Gi, Ti, Pi, Ei). -// The returned string is atmost 6 characters long. -// Requires n >= 0 -string formatIEC(int64_t n); - -} // namespace muduo - -#endif // MUDUO_BASE_LOGSTREAM_H diff --git a/include/muduo/base/Logging.cc b/include/muduo/base/Logging.cc deleted file mode 100644 index c09a8ce..0000000 --- a/include/muduo/base/Logging.cc +++ /dev/null @@ -1,227 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/Logging.h" - -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Timestamp.h" -#include "muduo/base/TimeZone.h" - -#include -#include -#include - -#include - -namespace muduo -{ - -/* -class LoggerImpl -{ - public: - typedef Logger::LogLevel LogLevel; - LoggerImpl(LogLevel level, int old_errno, const char* file, int line); - void finish(); - - Timestamp time_; - LogStream stream_; - LogLevel level_; - int line_; - const char* fullname_; - const char* basename_; -}; -*/ - -__thread char t_errnobuf[512]; -__thread char t_time[64]; -__thread time_t t_lastSecond; - -const char* strerror_tl(int savedErrno) -{ - return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); -} - -Logger::LogLevel initLogLevel() -{ - if (::getenv("MUDUO_LOG_TRACE")) - return Logger::TRACE; - else if (::getenv("MUDUO_LOG_DEBUG")) - return Logger::DEBUG; - else - return Logger::INFO; -} - -Logger::LogLevel g_logLevel = initLogLevel(); - -const char* LogLevelName[Logger::NUM_LOG_LEVELS] = -{ - "TRACE ", - "DEBUG ", - "INFO ", - "WARN ", - "ERROR ", - "FATAL ", -}; - -// helper class for known string length at compile time -class T -{ - public: - T(const char* str, unsigned len) - :str_(str), - len_(len) - { - assert(strlen(str) == len_); - } - - const char* str_; - const unsigned len_; -}; - -inline LogStream& operator<<(LogStream& s, T v) -{ - s.append(v.str_, v.len_); - return s; -} - -inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v) -{ - s.append(v.data_, v.size_); - return s; -} - -void defaultOutput(const char* msg, int len) -{ - size_t n = fwrite(msg, 1, len, stdout); - //FIXME check n - (void)n; -} - -void defaultFlush() -{ - fflush(stdout); -} - -Logger::OutputFunc g_output = defaultOutput; -Logger::FlushFunc g_flush = defaultFlush; -TimeZone g_logTimeZone; - -} // namespace muduo - -using namespace muduo; - -Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line) - : time_(Timestamp::now()), - stream_(), - level_(level), - line_(line), - basename_(file) -{ - formatTime(); - CurrentThread::tid(); - stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength()); - stream_ << T(LogLevelName[level], 6); - if (savedErrno != 0) - { - stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; - } -} - -void Logger::Impl::formatTime() -{ - int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch(); - time_t seconds = static_cast(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond); - int microseconds = static_cast(microSecondsSinceEpoch % Timestamp::kMicroSecondsPerSecond); - if (seconds != t_lastSecond) - { - t_lastSecond = seconds; - struct tm tm_time; - if (g_logTimeZone.valid()) - { - tm_time = g_logTimeZone.toLocalTime(seconds); - } - else - { - ::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime - } - - int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%02d", - tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, - tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); - assert(len == 17); (void)len; - } - - if (g_logTimeZone.valid()) - { - Fmt us(".%06d ", microseconds); - assert(us.length() == 8); - stream_ << T(t_time, 17) << T(us.data(), 8); - } - else - { - Fmt us(".%06dZ ", microseconds); - assert(us.length() == 9); - stream_ << T(t_time, 17) << T(us.data(), 9); - } -} - -void Logger::Impl::finish() -{ - stream_ << " - " << basename_ << ':' << line_ << '\n'; -} - -Logger::Logger(SourceFile file, int line) - : impl_(INFO, 0, file, line) -{ -} - -Logger::Logger(SourceFile file, int line, LogLevel level, const char* func) - : impl_(level, 0, file, line) -{ - impl_.stream_ << func << ' '; -} - -Logger::Logger(SourceFile file, int line, LogLevel level) - : impl_(level, 0, file, line) -{ -} - -Logger::Logger(SourceFile file, int line, bool toAbort) - : impl_(toAbort?FATAL:ERROR, errno, file, line) -{ -} - -Logger::~Logger() -{ - impl_.finish(); - const LogStream::Buffer& buf(stream().buffer()); - g_output(buf.data(), buf.length()); - if (impl_.level_ == FATAL) - { - g_flush(); - abort(); - } -} - -void Logger::setLogLevel(Logger::LogLevel level) -{ - g_logLevel = level; -} - -void Logger::setOutput(OutputFunc out) -{ - g_output = out; -} - -void Logger::setFlush(FlushFunc flush) -{ - g_flush = flush; -} - -void Logger::setTimeZone(const TimeZone& tz) -{ - g_logTimeZone = tz; -} diff --git a/include/muduo/base/Logging.h b/include/muduo/base/Logging.h deleted file mode 100644 index be56689..0000000 --- a/include/muduo/base/Logging.h +++ /dev/null @@ -1,159 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_LOGGING_H -#define MUDUO_BASE_LOGGING_H - -#include "muduo/base/LogStream.h" -#include "muduo/base/Timestamp.h" - -namespace muduo -{ - -class TimeZone; - -class Logger -{ - public: - enum LogLevel - { - TRACE, - DEBUG, - INFO, - WARN, - ERROR, - FATAL, - NUM_LOG_LEVELS, - }; - - // compile time calculation of basename of source file - class SourceFile - { - public: - template - SourceFile(const char (&arr)[N]) - : data_(arr), - size_(N-1) - { - const char* slash = strrchr(data_, '/'); // builtin function - if (slash) - { - data_ = slash + 1; - size_ -= static_cast(data_ - arr); - } - } - - explicit SourceFile(const char* filename) - : data_(filename) - { - const char* slash = strrchr(filename, '/'); - if (slash) - { - data_ = slash + 1; - } - size_ = static_cast(strlen(data_)); - } - - const char* data_; - int size_; - }; - - Logger(SourceFile file, int line); - Logger(SourceFile file, int line, LogLevel level); - Logger(SourceFile file, int line, LogLevel level, const char* func); - Logger(SourceFile file, int line, bool toAbort); - ~Logger(); - - LogStream& stream() { return impl_.stream_; } - - static LogLevel logLevel(); - static void setLogLevel(LogLevel level); - - typedef void (*OutputFunc)(const char* msg, int len); - typedef void (*FlushFunc)(); - static void setOutput(OutputFunc); - static void setFlush(FlushFunc); - static void setTimeZone(const TimeZone& tz); - - private: - -class Impl -{ - public: - typedef Logger::LogLevel LogLevel; - Impl(LogLevel level, int old_errno, const SourceFile& file, int line); - void formatTime(); - void finish(); - - Timestamp time_; - LogStream stream_; - LogLevel level_; - int line_; - SourceFile basename_; -}; - - Impl impl_; - -}; - -extern Logger::LogLevel g_logLevel; - -inline Logger::LogLevel Logger::logLevel() -{ - return g_logLevel; -} - -// -// CAUTION: do not write: -// -// if (good) -// LOG_INFO << "Good news"; -// else -// LOG_WARN << "Bad news"; -// -// this expends to -// -// if (good) -// if (logging_INFO) -// logInfoStream << "Good news"; -// else -// logWarnStream << "Bad news"; -// -#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \ - muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream() -#define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \ - muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream() -#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \ - muduo::Logger(__FILE__, __LINE__).stream() -#define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream() -#define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream() -#define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream() -#define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream() -#define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream() - -const char* strerror_tl(int savedErrno); - -// Taken from glog/logging.h -// -// Check that the input is non NULL. This very useful in constructor -// initializer lists. - -#define CHECK_NOTNULL(val) \ - ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) - -// A small helper for CHECK_NOTNULL(). -template -T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) -{ - if (ptr == NULL) - { - Logger(file, line, Logger::FATAL).stream() << names; - } - return ptr; -} - -} // namespace muduo - -#endif // MUDUO_BASE_LOGGING_H diff --git a/include/muduo/base/Mutex.h b/include/muduo/base/Mutex.h deleted file mode 100644 index 20746bd..0000000 --- a/include/muduo/base/Mutex.h +++ /dev/null @@ -1,233 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_MUTEX_H -#define MUDUO_BASE_MUTEX_H - -#include "muduo/base/CurrentThread.h" -#include "muduo/base/noncopyable.h" -#include -#include - -// Thread safety annotations { -// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html - -// Enable thread safety attributes only with clang. -// The attributes can be safely erased when compiling with other compilers. -#if defined(__clang__) && (!defined(SWIG)) -#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) -#else -#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op -#endif - -#define CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) - -#define SCOPED_CAPABILITY \ - THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) - -#define GUARDED_BY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) - -#define PT_GUARDED_BY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) - -#define ACQUIRED_BEFORE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) - -#define ACQUIRED_AFTER(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) - -#define REQUIRES(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) - -#define REQUIRES_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) - -#define ACQUIRE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) - -#define ACQUIRE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) - -#define RELEASE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) - -#define RELEASE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) - -#define TRY_ACQUIRE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) - -#define TRY_ACQUIRE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) - -#define EXCLUDES(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) - -#define ASSERT_CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) - -#define ASSERT_SHARED_CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) - -#define RETURN_CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) - -#define NO_THREAD_SAFETY_ANALYSIS \ - THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) - -// End of thread safety annotations } - -#ifdef CHECK_PTHREAD_RETURN_VALUE - -#ifdef NDEBUG -__BEGIN_DECLS -extern void __assert_perror_fail (int errnum, - const char *file, - unsigned int line, - const char *function) - noexcept __attribute__ ((__noreturn__)); -__END_DECLS -#endif - -#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ - if (__builtin_expect(errnum != 0, 0)) \ - __assert_perror_fail (errnum, __FILE__, __LINE__, __func__);}) - -#else // CHECK_PTHREAD_RETURN_VALUE - -#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ - assert(errnum == 0); (void) errnum;}) - -#endif // CHECK_PTHREAD_RETURN_VALUE - -namespace muduo -{ - -// Use as data member of a class, eg. -// -// class Foo -// { -// public: -// int size() const; -// -// private: -// mutable MutexLock mutex_; -// std::vector data_ GUARDED_BY(mutex_); -// }; -class CAPABILITY("mutex") MutexLock : noncopyable -{ - public: - MutexLock() - : holder_(0) - { - MCHECK(pthread_mutex_init(&mutex_, NULL)); - } - - ~MutexLock() - { - assert(holder_ == 0); - MCHECK(pthread_mutex_destroy(&mutex_)); - } - - // must be called when locked, i.e. for assertion - bool isLockedByThisThread() const - { - return holder_ == CurrentThread::tid(); - } - - void assertLocked() const ASSERT_CAPABILITY(this) - { - assert(isLockedByThisThread()); - } - - // internal usage - - void lock() ACQUIRE() - { - MCHECK(pthread_mutex_lock(&mutex_)); - assignHolder(); - } - - void unlock() RELEASE() - { - unassignHolder(); - MCHECK(pthread_mutex_unlock(&mutex_)); - } - - pthread_mutex_t* getPthreadMutex() /* non-const */ - { - return &mutex_; - } - - private: - friend class Condition; - - class UnassignGuard : noncopyable - { - public: - explicit UnassignGuard(MutexLock& owner) - : owner_(owner) - { - owner_.unassignHolder(); - } - - ~UnassignGuard() - { - owner_.assignHolder(); - } - - private: - MutexLock& owner_; - }; - - void unassignHolder() - { - holder_ = 0; - } - - void assignHolder() - { - holder_ = CurrentThread::tid(); - } - - pthread_mutex_t mutex_; - pid_t holder_; -}; - -// Use as a stack variable, eg. -// int Foo::size() const -// { -// MutexLockGuard lock(mutex_); -// return data_.size(); -// } -class SCOPED_CAPABILITY MutexLockGuard : noncopyable -{ - public: - explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex) - : mutex_(mutex) - { - mutex_.lock(); - } - - ~MutexLockGuard() RELEASE() - { - mutex_.unlock(); - } - - private: - - MutexLock& mutex_; -}; - -} // namespace muduo - -// Prevent misuse like: -// MutexLockGuard(mutex_); -// A tempory object doesn't hold the lock for long! -#define MutexLockGuard(x) error "Missing guard object name" - -#endif // MUDUO_BASE_MUTEX_H diff --git a/include/muduo/base/ProcessInfo.cc b/include/muduo/base/ProcessInfo.cc deleted file mode 100644 index 6ab5ad1..0000000 --- a/include/muduo/base/ProcessInfo.cc +++ /dev/null @@ -1,246 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/ProcessInfo.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/FileUtil.h" - -#include - -#include -#include -#include -#include // snprintf -#include -#include -#include -#include - -namespace muduo -{ -namespace detail -{ -__thread int t_numOpenedFiles = 0; -int fdDirFilter(const struct dirent* d) -{ - if (::isdigit(d->d_name[0])) - { - ++t_numOpenedFiles; - } - return 0; -} - -__thread std::vector* t_pids = NULL; -int taskDirFilter(const struct dirent* d) -{ - if (::isdigit(d->d_name[0])) - { - t_pids->push_back(atoi(d->d_name)); - } - return 0; -} - -int scanDir(const char *dirpath, int (*filter)(const struct dirent *)) -{ - struct dirent** namelist = NULL; - int result = ::scandir(dirpath, &namelist, filter, alphasort); - assert(namelist == NULL); - return result; -} - -Timestamp g_startTime = Timestamp::now(); -// assume those won't change during the life time of a process. -int g_clockTicks = static_cast(::sysconf(_SC_CLK_TCK)); -int g_pageSize = static_cast(::sysconf(_SC_PAGE_SIZE)); -} // namespace detail -} // namespace muduo - -using namespace muduo; -using namespace muduo::detail; - -pid_t ProcessInfo::pid() -{ - return ::getpid(); -} - -string ProcessInfo::pidString() -{ - char buf[32]; - snprintf(buf, sizeof buf, "%d", pid()); - return buf; -} - -uid_t ProcessInfo::uid() -{ - return ::getuid(); -} - -string ProcessInfo::username() -{ - struct passwd pwd; - struct passwd* result = NULL; - char buf[8192]; - const char* name = "unknownuser"; - - getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); - if (result) - { - name = pwd.pw_name; - } - return name; -} - -uid_t ProcessInfo::euid() -{ - return ::geteuid(); -} - -Timestamp ProcessInfo::startTime() -{ - return g_startTime; -} - -int ProcessInfo::clockTicksPerSecond() -{ - return g_clockTicks; -} - -int ProcessInfo::pageSize() -{ - return g_pageSize; -} - -bool ProcessInfo::isDebugBuild() -{ -#ifdef NDEBUG - return false; -#else - return true; -#endif -} - -string ProcessInfo::hostname() -{ - // HOST_NAME_MAX 64 - // _POSIX_HOST_NAME_MAX 255 - char buf[256]; - if (::gethostname(buf, sizeof buf) == 0) - { - buf[sizeof(buf)-1] = '\0'; - return buf; - } - else - { - return "unknownhost"; - } -} - -string ProcessInfo::procname() -{ - return procname(procStat()).as_string(); -} - -StringPiece ProcessInfo::procname(const string& stat) -{ - StringPiece name; - size_t lp = stat.find('('); - size_t rp = stat.rfind(')'); - if (lp != string::npos && rp != string::npos && lp < rp) - { - name.set(stat.data()+lp+1, static_cast(rp-lp-1)); - } - return name; -} - -string ProcessInfo::procStatus() -{ - string result; - FileUtil::readFile("/proc/self/status", 65536, &result); - return result; -} - -string ProcessInfo::procStat() -{ - string result; - FileUtil::readFile("/proc/self/stat", 65536, &result); - return result; -} - -string ProcessInfo::threadStat() -{ - char buf[64]; - snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid()); - string result; - FileUtil::readFile(buf, 65536, &result); - return result; -} - -string ProcessInfo::exePath() -{ - string result; - char buf[1024]; - ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf); - if (n > 0) - { - result.assign(buf, n); - } - return result; -} - -int ProcessInfo::openedFiles() -{ - t_numOpenedFiles = 0; - scanDir("/proc/self/fd", fdDirFilter); - return t_numOpenedFiles; -} - -int ProcessInfo::maxOpenFiles() -{ - struct rlimit rl; - if (::getrlimit(RLIMIT_NOFILE, &rl)) - { - return openedFiles(); - } - else - { - return static_cast(rl.rlim_cur); - } -} - -ProcessInfo::CpuTime ProcessInfo::cpuTime() -{ - ProcessInfo::CpuTime t; - struct tms tms; - if (::times(&tms) >= 0) - { - const double hz = static_cast(clockTicksPerSecond()); - t.userSeconds = static_cast(tms.tms_utime) / hz; - t.systemSeconds = static_cast(tms.tms_stime) / hz; - } - return t; -} - -int ProcessInfo::numThreads() -{ - int result = 0; - string status = procStatus(); - size_t pos = status.find("Threads:"); - if (pos != string::npos) - { - result = ::atoi(status.c_str() + pos + 8); - } - return result; -} - -std::vector ProcessInfo::threads() -{ - std::vector result; - t_pids = &result; - scanDir("/proc/self/task", taskDirFilter); - t_pids = NULL; - std::sort(result.begin(), result.end()); - return result; -} - diff --git a/include/muduo/base/ProcessInfo.h b/include/muduo/base/ProcessInfo.h deleted file mode 100644 index eae1498..0000000 --- a/include/muduo/base/ProcessInfo.h +++ /dev/null @@ -1,68 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_BASE_PROCESSINFO_H -#define MUDUO_BASE_PROCESSINFO_H - -#include "muduo/base/StringPiece.h" -#include "muduo/base/Types.h" -#include "muduo/base/Timestamp.h" -#include -#include - -namespace muduo -{ - -namespace ProcessInfo -{ - pid_t pid(); - string pidString(); - uid_t uid(); - string username(); - uid_t euid(); - Timestamp startTime(); - int clockTicksPerSecond(); - int pageSize(); - bool isDebugBuild(); // constexpr - - string hostname(); - string procname(); - StringPiece procname(const string& stat); - - /// read /proc/self/status - string procStatus(); - - /// read /proc/self/stat - string procStat(); - - /// read /proc/self/task/tid/stat - string threadStat(); - - /// readlink /proc/self/exe - string exePath(); - - int openedFiles(); - int maxOpenFiles(); - - struct CpuTime - { - double userSeconds; - double systemSeconds; - - CpuTime() : userSeconds(0.0), systemSeconds(0.0) { } - - double total() const { return userSeconds + systemSeconds; } - }; - CpuTime cpuTime(); - - int numThreads(); - std::vector threads(); -} // namespace ProcessInfo - -} // namespace muduo - -#endif // MUDUO_BASE_PROCESSINFO_H diff --git a/include/muduo/base/Singleton.h b/include/muduo/base/Singleton.h deleted file mode 100644 index 5949436..0000000 --- a/include/muduo/base/Singleton.h +++ /dev/null @@ -1,77 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_SINGLETON_H -#define MUDUO_BASE_SINGLETON_H - -#include "muduo/base/noncopyable.h" - -#include -#include -#include // atexit - -namespace muduo -{ - -namespace detail -{ -// This doesn't detect inherited member functions! -// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions -template -struct has_no_destroy -{ - template static char test(decltype(&C::no_destroy)); - template static int32_t test(...); - const static bool value = sizeof(test(0)) == 1; -}; -} // namespace detail - -template -class Singleton : noncopyable -{ - public: - Singleton() = delete; - ~Singleton() = delete; - - static T& instance() - { - pthread_once(&ponce_, &Singleton::init); - assert(value_ != NULL); - return *value_; - } - - private: - static void init() - { - value_ = new T(); - if (!detail::has_no_destroy::value) - { - ::atexit(destroy); - } - } - - static void destroy() - { - typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; - T_must_be_complete_type dummy; (void) dummy; - - delete value_; - value_ = NULL; - } - - private: - static pthread_once_t ponce_; - static T* value_; -}; - -template -pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT; - -template -T* Singleton::value_ = NULL; - -} // namespace muduo - -#endif // MUDUO_BASE_SINGLETON_H diff --git a/include/muduo/base/StringPiece.h b/include/muduo/base/StringPiece.h deleted file mode 100644 index a62eda0..0000000 --- a/include/muduo/base/StringPiece.h +++ /dev/null @@ -1,189 +0,0 @@ -// Taken from PCRE pcre_stringpiece.h -// -// Copyright (c) 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: Sanjay Ghemawat -// -// A string like object that points into another piece of memory. -// Useful for providing an interface that allows clients to easily -// pass in either a "const char*" or a "string". -// -// Arghh! I wish C++ literals were automatically of type "string". - -#ifndef MUDUO_BASE_STRINGPIECE_H -#define MUDUO_BASE_STRINGPIECE_H - -#include -#include // for ostream forward-declaration - -#include "muduo/base/Types.h" - -namespace muduo -{ - -// For passing C-style string argument to a function. -class StringArg // copyable -{ - public: - StringArg(const char* str) - : str_(str) - { } - - StringArg(const string& str) - : str_(str.c_str()) - { } - - const char* c_str() const { return str_; } - - private: - const char* str_; -}; - -class StringPiece { - private: - const char* ptr_; - int length_; - - public: - // We provide non-explicit singleton constructors so users can pass - // in a "const char*" or a "string" wherever a "StringPiece" is - // expected. - StringPiece() - : ptr_(NULL), length_(0) { } - StringPiece(const char* str) - : ptr_(str), length_(static_cast(strlen(ptr_))) { } - StringPiece(const unsigned char* str) - : ptr_(reinterpret_cast(str)), - length_(static_cast(strlen(ptr_))) { } - StringPiece(const string& str) - : ptr_(str.data()), length_(static_cast(str.size())) { } - StringPiece(const char* offset, int len) - : ptr_(offset), length_(len) { } - - // data() may return a pointer to a buffer with embedded NULs, and the - // returned buffer may or may not be null terminated. Therefore it is - // typically a mistake to pass data() to a routine that expects a NUL - // terminated string. Use "as_string().c_str()" if you really need to do - // this. Or better yet, change your routine so it does not rely on NUL - // termination. - const char* data() const { return ptr_; } - int size() const { return length_; } - bool empty() const { return length_ == 0; } - const char* begin() const { return ptr_; } - const char* end() const { return ptr_ + length_; } - - void clear() { ptr_ = NULL; length_ = 0; } - void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; } - void set(const char* str) { - ptr_ = str; - length_ = static_cast(strlen(str)); - } - void set(const void* buffer, int len) { - ptr_ = reinterpret_cast(buffer); - length_ = len; - } - - char operator[](int i) const { return ptr_[i]; } - - void remove_prefix(int n) { - ptr_ += n; - length_ -= n; - } - - void remove_suffix(int n) { - length_ -= n; - } - - bool operator==(const StringPiece& x) const { - return ((length_ == x.length_) && - (memcmp(ptr_, x.ptr_, length_) == 0)); - } - bool operator!=(const StringPiece& x) const { - return !(*this == x); - } - -#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \ - bool operator cmp (const StringPiece& x) const { \ - int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \ - return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \ - } - STRINGPIECE_BINARY_PREDICATE(<, <); - STRINGPIECE_BINARY_PREDICATE(<=, <); - STRINGPIECE_BINARY_PREDICATE(>=, >); - STRINGPIECE_BINARY_PREDICATE(>, >); -#undef STRINGPIECE_BINARY_PREDICATE - - int compare(const StringPiece& x) const { - int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); - if (r == 0) { - if (length_ < x.length_) r = -1; - else if (length_ > x.length_) r = +1; - } - return r; - } - - string as_string() const { - return string(data(), size()); - } - - void CopyToString(string* target) const { - target->assign(ptr_, length_); - } - - // Does "this" start with "x" - bool starts_with(const StringPiece& x) const { - return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0)); - } -}; - -} // namespace muduo - -// ------------------------------------------------------------------ -// Functions used to create STL containers that use StringPiece -// Remember that a StringPiece's lifetime had better be less than -// that of the underlying string or char*. If it is not, then you -// cannot safely store a StringPiece into an STL container -// ------------------------------------------------------------------ - -#ifdef HAVE_TYPE_TRAITS -// This makes vector really fast for some STL implementations -template<> struct __type_traits { - typedef __true_type has_trivial_default_constructor; - typedef __true_type has_trivial_copy_constructor; - typedef __true_type has_trivial_assignment_operator; - typedef __true_type has_trivial_destructor; - typedef __true_type is_POD_type; -}; -#endif - -// allow StringPiece to be logged -std::ostream& operator<<(std::ostream& o, const muduo::StringPiece& piece); - -#endif // MUDUO_BASE_STRINGPIECE_H diff --git a/include/muduo/base/Thread.cc b/include/muduo/base/Thread.cc deleted file mode 100644 index 630a0c9..0000000 --- a/include/muduo/base/Thread.cc +++ /dev/null @@ -1,200 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/Thread.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Exception.h" -#include "muduo/base/Logging.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace muduo -{ -namespace detail -{ - -pid_t gettid() -{ - return static_cast(::syscall(SYS_gettid)); -} - -void afterFork() -{ - muduo::CurrentThread::t_cachedTid = 0; - muduo::CurrentThread::t_threadName = "main"; - CurrentThread::tid(); - // no need to call pthread_atfork(NULL, NULL, &afterFork); -} - -class ThreadNameInitializer -{ - public: - ThreadNameInitializer() - { - muduo::CurrentThread::t_threadName = "main"; - CurrentThread::tid(); - pthread_atfork(NULL, NULL, &afterFork); - } -}; - -ThreadNameInitializer init; - -struct ThreadData -{ - typedef muduo::Thread::ThreadFunc ThreadFunc; - ThreadFunc func_; - string name_; - pid_t* tid_; - CountDownLatch* latch_; - - ThreadData(ThreadFunc func, - const string& name, - pid_t* tid, - CountDownLatch* latch) - : func_(std::move(func)), - name_(name), - tid_(tid), - latch_(latch) - { } - - void runInThread() - { - *tid_ = muduo::CurrentThread::tid(); - tid_ = NULL; - latch_->countDown(); - latch_ = NULL; - - muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str(); - ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName); - try - { - func_(); - muduo::CurrentThread::t_threadName = "finished"; - } - catch (const Exception& ex) - { - muduo::CurrentThread::t_threadName = "crashed"; - fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); - fprintf(stderr, "reason: %s\n", ex.what()); - fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); - abort(); - } - catch (const std::exception& ex) - { - muduo::CurrentThread::t_threadName = "crashed"; - fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); - fprintf(stderr, "reason: %s\n", ex.what()); - abort(); - } - catch (...) - { - muduo::CurrentThread::t_threadName = "crashed"; - fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str()); - throw; // rethrow - } - } -}; - -void* startThread(void* obj) -{ - ThreadData* data = static_cast(obj); - data->runInThread(); - delete data; - return NULL; -} - -} // namespace detail - -void CurrentThread::cacheTid() -{ - if (t_cachedTid == 0) - { - t_cachedTid = detail::gettid(); - t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); - } -} - -bool CurrentThread::isMainThread() -{ - return tid() == ::getpid(); -} - -void CurrentThread::sleepUsec(int64_t usec) -{ - struct timespec ts = { 0, 0 }; - ts.tv_sec = static_cast(usec / Timestamp::kMicroSecondsPerSecond); - ts.tv_nsec = static_cast(usec % Timestamp::kMicroSecondsPerSecond * 1000); - ::nanosleep(&ts, NULL); -} - -AtomicInt32 Thread::numCreated_; - -Thread::Thread(ThreadFunc func, const string& n) - : started_(false), - joined_(false), - pthreadId_(0), - tid_(0), - func_(std::move(func)), - name_(n), - latch_(1) -{ - setDefaultName(); -} - -Thread::~Thread() -{ - if (started_ && !joined_) - { - pthread_detach(pthreadId_); - } -} - -void Thread::setDefaultName() -{ - int num = numCreated_.incrementAndGet(); - if (name_.empty()) - { - char buf[32]; - snprintf(buf, sizeof buf, "Thread%d", num); - name_ = buf; - } -} - -void Thread::start() -{ - assert(!started_); - started_ = true; - // FIXME: move(func_) - detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_); - if (pthread_create(&pthreadId_, NULL, &detail::startThread, data)) - { - started_ = false; - delete data; // or no delete? - LOG_SYSFATAL << "Failed in pthread_create"; - } - else - { - latch_.wait(); - assert(tid_ > 0); - } -} - -int Thread::join() -{ - assert(started_); - assert(!joined_); - joined_ = true; - return pthread_join(pthreadId_, NULL); -} - -} // namespace muduo diff --git a/include/muduo/base/Thread.h b/include/muduo/base/Thread.h deleted file mode 100644 index d2305a2..0000000 --- a/include/muduo/base/Thread.h +++ /dev/null @@ -1,54 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_THREAD_H -#define MUDUO_BASE_THREAD_H - -#include "muduo/base/Atomic.h" -#include "muduo/base/CountDownLatch.h" -#include "muduo/base/Types.h" - -#include -#include -#include - -namespace muduo -{ - -class Thread : noncopyable -{ - public: - typedef std::function ThreadFunc; - - explicit Thread(ThreadFunc, const string& name = string()); - // FIXME: make it movable in C++11 - ~Thread(); - - void start(); - int join(); // return pthread_join() - - bool started() const { return started_; } - // pthread_t pthreadId() const { return pthreadId_; } - pid_t tid() const { return tid_; } - const string& name() const { return name_; } - - static int numCreated() { return numCreated_.get(); } - - private: - void setDefaultName(); - - bool started_; - bool joined_; - pthread_t pthreadId_; - pid_t tid_; - ThreadFunc func_; - string name_; - CountDownLatch latch_; - - static AtomicInt32 numCreated_; -}; - -} // namespace muduo -#endif // MUDUO_BASE_THREAD_H diff --git a/include/muduo/base/ThreadLocal.h b/include/muduo/base/ThreadLocal.h deleted file mode 100644 index b8283bc..0000000 --- a/include/muduo/base/ThreadLocal.h +++ /dev/null @@ -1,59 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_THREADLOCAL_H -#define MUDUO_BASE_THREADLOCAL_H - -#include "muduo/base/Mutex.h" -#include "muduo/base/noncopyable.h" - -#include - -namespace muduo -{ - -template -class ThreadLocal : noncopyable -{ - public: - ThreadLocal() - { - MCHECK(pthread_key_create(&pkey_, &ThreadLocal::destructor)); - } - - ~ThreadLocal() - { - MCHECK(pthread_key_delete(pkey_)); - } - - T& value() - { - T* perThreadValue = static_cast(pthread_getspecific(pkey_)); - if (!perThreadValue) - { - T* newObj = new T(); - MCHECK(pthread_setspecific(pkey_, newObj)); - perThreadValue = newObj; - } - return *perThreadValue; - } - - private: - - static void destructor(void *x) - { - T* obj = static_cast(x); - typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; - T_must_be_complete_type dummy; (void) dummy; - delete obj; - } - - private: - pthread_key_t pkey_; -}; - -} // namespace muduo - -#endif // MUDUO_BASE_THREADLOCAL_H diff --git a/include/muduo/base/ThreadLocalSingleton.h b/include/muduo/base/ThreadLocalSingleton.h deleted file mode 100644 index 5c544df..0000000 --- a/include/muduo/base/ThreadLocalSingleton.h +++ /dev/null @@ -1,82 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_THREADLOCALSINGLETON_H -#define MUDUO_BASE_THREADLOCALSINGLETON_H - -#include "muduo/base/noncopyable.h" - -#include -#include - -namespace muduo -{ - -template -class ThreadLocalSingleton : noncopyable -{ - public: - ThreadLocalSingleton() = delete; - ~ThreadLocalSingleton() = delete; - - static T& instance() - { - if (!t_value_) - { - t_value_ = new T(); - deleter_.set(t_value_); - } - return *t_value_; - } - - static T* pointer() - { - return t_value_; - } - - private: - static void destructor(void* obj) - { - assert(obj == t_value_); - typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; - T_must_be_complete_type dummy; (void) dummy; - delete t_value_; - t_value_ = 0; - } - - class Deleter - { - public: - Deleter() - { - pthread_key_create(&pkey_, &ThreadLocalSingleton::destructor); - } - - ~Deleter() - { - pthread_key_delete(pkey_); - } - - void set(T* newObj) - { - assert(pthread_getspecific(pkey_) == NULL); - pthread_setspecific(pkey_, newObj); - } - - pthread_key_t pkey_; - }; - - static __thread T* t_value_; - static Deleter deleter_; -}; - -template -__thread T* ThreadLocalSingleton::t_value_ = 0; - -template -typename ThreadLocalSingleton::Deleter ThreadLocalSingleton::deleter_; - -} // namespace muduo -#endif // MUDUO_BASE_THREADLOCALSINGLETON_H diff --git a/include/muduo/base/ThreadPool.cc b/include/muduo/base/ThreadPool.cc deleted file mode 100644 index 6905dd7..0000000 --- a/include/muduo/base/ThreadPool.cc +++ /dev/null @@ -1,156 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/ThreadPool.h" - -#include "muduo/base/Exception.h" - -#include -#include - -using namespace muduo; - -ThreadPool::ThreadPool(const string& nameArg) - : mutex_(), - notEmpty_(mutex_), - notFull_(mutex_), - name_(nameArg), - maxQueueSize_(0), - running_(false) -{ -} - -ThreadPool::~ThreadPool() -{ - if (running_) - { - stop(); - } -} - -void ThreadPool::start(int numThreads) -{ - assert(threads_.empty()); - running_ = true; - threads_.reserve(numThreads); - for (int i = 0; i < numThreads; ++i) - { - char id[32]; - snprintf(id, sizeof id, "%d", i+1); - threads_.emplace_back(new muduo::Thread( - std::bind(&ThreadPool::runInThread, this), name_+id)); - threads_[i]->start(); - } - if (numThreads == 0 && threadInitCallback_) - { - threadInitCallback_(); - } -} - -void ThreadPool::stop() -{ - { - MutexLockGuard lock(mutex_); - running_ = false; - notEmpty_.notifyAll(); - notFull_.notifyAll(); - } - for (auto& thr : threads_) - { - thr->join(); - } -} - -size_t ThreadPool::queueSize() const -{ - MutexLockGuard lock(mutex_); - return queue_.size(); -} - -void ThreadPool::run(Task task) -{ - if (threads_.empty()) - { - task(); - } - else - { - MutexLockGuard lock(mutex_); - while (isFull() && running_) - { - notFull_.wait(); - } - if (!running_) return; - assert(!isFull()); - - queue_.push_back(std::move(task)); - notEmpty_.notify(); - } -} - -ThreadPool::Task ThreadPool::take() -{ - MutexLockGuard lock(mutex_); - // always use a while-loop, due to spurious wakeup - while (queue_.empty() && running_) - { - notEmpty_.wait(); - } - Task task; - if (!queue_.empty()) - { - task = queue_.front(); - queue_.pop_front(); - if (maxQueueSize_ > 0) - { - notFull_.notify(); - } - } - return task; -} - -bool ThreadPool::isFull() const -{ - mutex_.assertLocked(); - return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_; -} - -void ThreadPool::runInThread() -{ - try - { - if (threadInitCallback_) - { - threadInitCallback_(); - } - while (running_) - { - Task task(take()); - if (task) - { - task(); - } - } - } - catch (const Exception& ex) - { - fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); - fprintf(stderr, "reason: %s\n", ex.what()); - fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); - abort(); - } - catch (const std::exception& ex) - { - fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); - fprintf(stderr, "reason: %s\n", ex.what()); - abort(); - } - catch (...) - { - fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str()); - throw; // rethrow - } -} - diff --git a/include/muduo/base/ThreadPool.h b/include/muduo/base/ThreadPool.h deleted file mode 100644 index 385c1bb..0000000 --- a/include/muduo/base/ThreadPool.h +++ /dev/null @@ -1,67 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_THREADPOOL_H -#define MUDUO_BASE_THREADPOOL_H - -#include "muduo/base/Condition.h" -#include "muduo/base/Mutex.h" -#include "muduo/base/Thread.h" -#include "muduo/base/Types.h" - -#include -#include - -namespace muduo -{ - -class ThreadPool : noncopyable -{ - public: - typedef std::function Task; - - explicit ThreadPool(const string& nameArg = string("ThreadPool")); - ~ThreadPool(); - - // Must be called before start(). - void setMaxQueueSize(int maxSize) { maxQueueSize_ = maxSize; } - void setThreadInitCallback(const Task& cb) - { threadInitCallback_ = cb; } - - void start(int numThreads); - void stop(); - - const string& name() const - { return name_; } - - size_t queueSize() const; - - // Could block if maxQueueSize > 0 - // Call after stop() will return immediately. - // There is no move-only version of std::function in C++ as of C++14. - // So we don't need to overload a const& and an && versions - // as we do in (Bounded)BlockingQueue. - // https://stackoverflow.com/a/25408989 - void run(Task f); - - private: - bool isFull() const REQUIRES(mutex_); - void runInThread(); - Task take(); - - mutable MutexLock mutex_; - Condition notEmpty_ GUARDED_BY(mutex_); - Condition notFull_ GUARDED_BY(mutex_); - string name_; - Task threadInitCallback_; - std::vector> threads_; - std::deque queue_ GUARDED_BY(mutex_); - size_t maxQueueSize_; - bool running_; -}; - -} // namespace muduo - -#endif // MUDUO_BASE_THREADPOOL_H diff --git a/include/muduo/base/TimeZone.cc b/include/muduo/base/TimeZone.cc deleted file mode 100644 index 9544385..0000000 --- a/include/muduo/base/TimeZone.cc +++ /dev/null @@ -1,363 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/TimeZone.h" -#include "muduo/base/noncopyable.h" -#include "muduo/base/Date.h" - -#include -#include -#include -#include - -#include -//#define _BSD_SOURCE -#include - -#include -#include - -namespace muduo -{ -namespace detail -{ - -struct Transition -{ - time_t gmttime; - time_t localtime; - int localtimeIdx; - - Transition(time_t t, time_t l, int localIdx) - : gmttime(t), localtime(l), localtimeIdx(localIdx) - { } - -}; - -struct Comp -{ - bool compareGmt; - - Comp(bool gmt) - : compareGmt(gmt) - { - } - - bool operator()(const Transition& lhs, const Transition& rhs) const - { - if (compareGmt) - return lhs.gmttime < rhs.gmttime; - else - return lhs.localtime < rhs.localtime; - } - - bool equal(const Transition& lhs, const Transition& rhs) const - { - if (compareGmt) - return lhs.gmttime == rhs.gmttime; - else - return lhs.localtime == rhs.localtime; - } -}; - -struct Localtime -{ - time_t gmtOffset; - bool isDst; - int arrbIdx; - - Localtime(time_t offset, bool dst, int arrb) - : gmtOffset(offset), isDst(dst), arrbIdx(arrb) - { } -}; - -inline void fillHMS(unsigned seconds, struct tm* utc) -{ - utc->tm_sec = seconds % 60; - unsigned minutes = seconds / 60; - utc->tm_min = minutes % 60; - utc->tm_hour = minutes / 60; -} - -} // namespace detail -const int kSecondsPerDay = 24*60*60; -} // namespace muduo - -using namespace muduo; -using namespace std; - -struct TimeZone::Data -{ - vector transitions; - vector localtimes; - vector names; - string abbreviation; -}; - -namespace muduo -{ -namespace detail -{ - -class File : noncopyable -{ - public: - File(const char* file) - : fp_(::fopen(file, "rb")) - { - } - - ~File() - { - if (fp_) - { - ::fclose(fp_); - } - } - - bool valid() const { return fp_; } - - string readBytes(int n) - { - char buf[n]; - ssize_t nr = ::fread(buf, 1, n, fp_); - if (nr != n) - throw logic_error("no enough data"); - return string(buf, n); - } - - int32_t readInt32() - { - int32_t x = 0; - ssize_t nr = ::fread(&x, 1, sizeof(int32_t), fp_); - if (nr != sizeof(int32_t)) - throw logic_error("bad int32_t data"); - return be32toh(x); - } - - uint8_t readUInt8() - { - uint8_t x = 0; - ssize_t nr = ::fread(&x, 1, sizeof(uint8_t), fp_); - if (nr != sizeof(uint8_t)) - throw logic_error("bad uint8_t data"); - return x; - } - - private: - FILE* fp_; -}; - -bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) -{ - File f(zonefile); - if (f.valid()) - { - try - { - string head = f.readBytes(4); - if (head != "TZif") - throw logic_error("bad head"); - string version = f.readBytes(1); - f.readBytes(15); - - int32_t isgmtcnt = f.readInt32(); - int32_t isstdcnt = f.readInt32(); - int32_t leapcnt = f.readInt32(); - int32_t timecnt = f.readInt32(); - int32_t typecnt = f.readInt32(); - int32_t charcnt = f.readInt32(); - - vector trans; - vector localtimes; - trans.reserve(timecnt); - for (int i = 0; i < timecnt; ++i) - { - trans.push_back(f.readInt32()); - } - - for (int i = 0; i < timecnt; ++i) - { - uint8_t local = f.readUInt8(); - localtimes.push_back(local); - } - - for (int i = 0; i < typecnt; ++i) - { - int32_t gmtoff = f.readInt32(); - uint8_t isdst = f.readUInt8(); - uint8_t abbrind = f.readUInt8(); - - data->localtimes.push_back(Localtime(gmtoff, isdst, abbrind)); - } - - for (int i = 0; i < timecnt; ++i) - { - int localIdx = localtimes[i]; - time_t localtime = trans[i] + data->localtimes[localIdx].gmtOffset; - data->transitions.push_back(Transition(trans[i], localtime, localIdx)); - } - - data->abbreviation = f.readBytes(charcnt); - - // leapcnt - for (int i = 0; i < leapcnt; ++i) - { - // int32_t leaptime = f.readInt32(); - // int32_t cumleap = f.readInt32(); - } - // FIXME - (void) isstdcnt; - (void) isgmtcnt; - } - catch (logic_error& e) - { - fprintf(stderr, "%s\n", e.what()); - } - } - return true; -} - -const Localtime* findLocaltime(const TimeZone::Data& data, Transition sentry, Comp comp) -{ - const Localtime* local = NULL; - - if (data.transitions.empty() || comp(sentry, data.transitions.front())) - { - // FIXME: should be first non dst time zone - local = &data.localtimes.front(); - } - else - { - vector::const_iterator transI = lower_bound(data.transitions.begin(), - data.transitions.end(), - sentry, - comp); - if (transI != data.transitions.end()) - { - if (!comp.equal(sentry, *transI)) - { - assert(transI != data.transitions.begin()); - --transI; - } - local = &data.localtimes[transI->localtimeIdx]; - } - else - { - // FIXME: use TZ-env - local = &data.localtimes[data.transitions.back().localtimeIdx]; - } - } - - return local; -} - -} // namespace detail -} // namespace muduo - - -TimeZone::TimeZone(const char* zonefile) - : data_(new TimeZone::Data) -{ - if (!detail::readTimeZoneFile(zonefile, data_.get())) - { - data_.reset(); - } -} - -TimeZone::TimeZone(int eastOfUtc, const char* name) - : data_(new TimeZone::Data) -{ - data_->localtimes.push_back(detail::Localtime(eastOfUtc, false, 0)); - data_->abbreviation = name; -} - -struct tm TimeZone::toLocalTime(time_t seconds) const -{ - struct tm localTime; - memZero(&localTime, sizeof(localTime)); - assert(data_ != NULL); - const Data& data(*data_); - - detail::Transition sentry(seconds, 0, 0); - const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(true)); - - if (local) - { - time_t localSeconds = seconds + local->gmtOffset; - ::gmtime_r(&localSeconds, &localTime); // FIXME: fromUtcTime - localTime.tm_isdst = local->isDst; - localTime.tm_gmtoff = local->gmtOffset; - localTime.tm_zone = &data.abbreviation[local->arrbIdx]; - } - - return localTime; -} - -time_t TimeZone::fromLocalTime(const struct tm& localTm) const -{ - assert(data_ != NULL); - const Data& data(*data_); - - struct tm tmp = localTm; - time_t seconds = ::timegm(&tmp); // FIXME: toUtcTime - detail::Transition sentry(0, seconds, 0); - const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(false)); - if (localTm.tm_isdst) - { - struct tm tryTm = toLocalTime(seconds - local->gmtOffset); - if (!tryTm.tm_isdst - && tryTm.tm_hour == localTm.tm_hour - && tryTm.tm_min == localTm.tm_min) - { - // FIXME: HACK - seconds -= 3600; - } - } - return seconds - local->gmtOffset; -} - -struct tm TimeZone::toUtcTime(time_t secondsSinceEpoch, bool yday) -{ - struct tm utc; - memZero(&utc, sizeof(utc)); - utc.tm_zone = "GMT"; - int seconds = static_cast(secondsSinceEpoch % kSecondsPerDay); - int days = static_cast(secondsSinceEpoch / kSecondsPerDay); - if (seconds < 0) - { - seconds += kSecondsPerDay; - --days; - } - detail::fillHMS(seconds, &utc); - Date date(days + Date::kJulianDayOf1970_01_01); - Date::YearMonthDay ymd = date.yearMonthDay(); - utc.tm_year = ymd.year - 1900; - utc.tm_mon = ymd.month - 1; - utc.tm_mday = ymd.day; - utc.tm_wday = date.weekDay(); - - if (yday) - { - Date startOfYear(ymd.year, 1, 1); - utc.tm_yday = date.julianDayNumber() - startOfYear.julianDayNumber(); - } - return utc; -} - -time_t TimeZone::fromUtcTime(const struct tm& utc) -{ - return fromUtcTime(utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, - utc.tm_hour, utc.tm_min, utc.tm_sec); -} - -time_t TimeZone::fromUtcTime(int year, int month, int day, - int hour, int minute, int seconds) -{ - Date date(year, month, day); - int secondsInDay = hour * 3600 + minute * 60 + seconds; - time_t days = date.julianDayNumber() - Date::kJulianDayOf1970_01_01; - return days * kSecondsPerDay + secondsInDay; -} diff --git a/include/muduo/base/TimeZone.h b/include/muduo/base/TimeZone.h deleted file mode 100644 index 6586630..0000000 --- a/include/muduo/base/TimeZone.h +++ /dev/null @@ -1,52 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_TIMEZONE_H -#define MUDUO_BASE_TIMEZONE_H - -#include "muduo/base/copyable.h" -#include -#include - -namespace muduo -{ - -// TimeZone for 1970~2030 -class TimeZone : public muduo::copyable -{ - public: - explicit TimeZone(const char* zonefile); - TimeZone(int eastOfUtc, const char* tzname); // a fixed timezone - TimeZone() = default; // an invalid timezone - - // default copy ctor/assignment/dtor are Okay. - - bool valid() const - { - // 'explicit operator bool() const' in C++11 - return static_cast(data_); - } - - struct tm toLocalTime(time_t secondsSinceEpoch) const; - time_t fromLocalTime(const struct tm&) const; - - // gmtime(3) - static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); - // timegm(3) - static time_t fromUtcTime(const struct tm&); - // year in [1900..2500], month in [1..12], day in [1..31] - static time_t fromUtcTime(int year, int month, int day, - int hour, int minute, int seconds); - - struct Data; - - private: - - std::shared_ptr data_; -}; - -} // namespace muduo - -#endif // MUDUO_BASE_TIMEZONE_H diff --git a/include/muduo/base/Timestamp.cc b/include/muduo/base/Timestamp.cc deleted file mode 100644 index fc0ed70..0000000 --- a/include/muduo/base/Timestamp.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/Timestamp.h" - -#include -#include - -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif - -#include - -using namespace muduo; - -static_assert(sizeof(Timestamp) == sizeof(int64_t), - "Timestamp should be same size as int64_t"); - -string Timestamp::toString() const -{ - char buf[32] = {0}; - int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; - int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; - snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, microseconds); - return buf; -} - -string Timestamp::toFormattedString(bool showMicroseconds) const -{ - char buf[64] = {0}; - time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); - struct tm tm_time; - gmtime_r(&seconds, &tm_time); - - if (showMicroseconds) - { - int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond); - snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", - tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, - tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, - microseconds); - } - else - { - snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", - tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, - tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); - } - return buf; -} - -Timestamp Timestamp::now() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - int64_t seconds = tv.tv_sec; - return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); -} - diff --git a/include/muduo/base/Timestamp.h b/include/muduo/base/Timestamp.h deleted file mode 100644 index ccb522d..0000000 --- a/include/muduo/base/Timestamp.h +++ /dev/null @@ -1,123 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_TIMESTAMP_H -#define MUDUO_BASE_TIMESTAMP_H - -#include "muduo/base/copyable.h" -#include "muduo/base/Types.h" - -#include - -namespace muduo -{ - -/// -/// Time stamp in UTC, in microseconds resolution. -/// -/// This class is immutable. -/// It's recommended to pass it by value, since it's passed in register on x64. -/// -class Timestamp : public muduo::copyable, - public boost::equality_comparable, - public boost::less_than_comparable -{ - public: - /// - /// Constucts an invalid Timestamp. - /// - Timestamp() - : microSecondsSinceEpoch_(0) - { - } - - /// - /// Constucts a Timestamp at specific time - /// - /// @param microSecondsSinceEpoch - explicit Timestamp(int64_t microSecondsSinceEpochArg) - : microSecondsSinceEpoch_(microSecondsSinceEpochArg) - { - } - - void swap(Timestamp& that) - { - std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); - } - - // default copy/assignment/dtor are Okay - - string toString() const; - string toFormattedString(bool showMicroseconds = true) const; - - bool valid() const { return microSecondsSinceEpoch_ > 0; } - - // for internal usage. - int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } - time_t secondsSinceEpoch() const - { return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); } - - /// - /// Get time of now. - /// - static Timestamp now(); - static Timestamp invalid() - { - return Timestamp(); - } - - static Timestamp fromUnixTime(time_t t) - { - return fromUnixTime(t, 0); - } - - static Timestamp fromUnixTime(time_t t, int microseconds) - { - return Timestamp(static_cast(t) * kMicroSecondsPerSecond + microseconds); - } - - static const int kMicroSecondsPerSecond = 1000 * 1000; - - private: - int64_t microSecondsSinceEpoch_; -}; - -inline bool operator<(Timestamp lhs, Timestamp rhs) -{ - return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); -} - -inline bool operator==(Timestamp lhs, Timestamp rhs) -{ - return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); -} - -/// -/// Gets time difference of two timestamps, result in seconds. -/// -/// @param high, low -/// @return (high-low) in seconds -/// @c double has 52-bit precision, enough for one-microsecond -/// resolution for next 100 years. -inline double timeDifference(Timestamp high, Timestamp low) -{ - int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); - return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; -} - -/// -/// Add @c seconds to given timestamp. -/// -/// @return timestamp+seconds as Timestamp -/// -inline Timestamp addTime(Timestamp timestamp, double seconds) -{ - int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); - return Timestamp(timestamp.microSecondsSinceEpoch() + delta); -} - -} // namespace muduo - -#endif // MUDUO_BASE_TIMESTAMP_H diff --git a/include/muduo/base/Types.h b/include/muduo/base/Types.h deleted file mode 100644 index ad94756..0000000 --- a/include/muduo/base/Types.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef MUDUO_BASE_TYPES_H -#define MUDUO_BASE_TYPES_H - -#include -#include // memset -#include - -#ifndef NDEBUG -#include -#endif - -/// -/// The most common stuffs. -/// -namespace muduo -{ - -using std::string; - -inline void memZero(void* p, size_t n) -{ - memset(p, 0, n); -} - -// Taken from google-protobuf stubs/common.h -// -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) and others -// -// Contains basic types and utilities used by the rest of the library. - -// -// Use implicit_cast as a safe version of static_cast or const_cast -// for upcasting in the type hierarchy (i.e. casting a pointer to Foo -// to a pointer to SuperclassOfFoo or casting a pointer to Foo to -// a const pointer to Foo). -// When you use implicit_cast, the compiler checks that the cast is safe. -// Such explicit implicit_casts are necessary in surprisingly many -// situations where C++ demands an exact type match instead of an -// argument type convertable to a target type. -// -// The From type can be inferred, so the preferred syntax for using -// implicit_cast is the same as for static_cast etc.: -// -// implicit_cast(expr) -// -// implicit_cast would have been part of the C++ standard library, -// but the proposal was submitted too late. It will probably make -// its way into the language in the future. -template -inline To implicit_cast(From const &f) -{ - return f; -} - -// When you upcast (that is, cast a pointer from type Foo to type -// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts -// always succeed. When you downcast (that is, cast a pointer from -// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because -// how do you know the pointer is really of type SubclassOfFoo? It -// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, -// when you downcast, you should use this macro. In debug mode, we -// use dynamic_cast<> to double-check the downcast is legal (we die -// if it's not). In normal mode, we do the efficient static_cast<> -// instead. Thus, it's important to test in debug mode to make sure -// the cast is legal! -// This is the only place in the code we should use dynamic_cast<>. -// In particular, you SHOULDN'T be using dynamic_cast<> in order to -// do RTTI (eg code like this: -// if (dynamic_cast(foo)) HandleASubclass1Object(foo); -// if (dynamic_cast(foo)) HandleASubclass2Object(foo); -// You should design the code some other way not to need this. - -template // use like this: down_cast(foo); -inline To down_cast(From* f) // so we only accept pointers -{ - // Ensures that To is a sub-type of From *. This test is here only - // for compile-time type checking, and has no overhead in an - // optimized build at run-time, as it will be optimized away - // completely. - if (false) - { - implicit_cast(0); - } - -#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) - assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! -#endif - return static_cast(f); -} - -} // namespace muduo - -#endif // MUDUO_BASE_TYPES_H diff --git a/include/muduo/base/WeakCallback.h b/include/muduo/base/WeakCallback.h deleted file mode 100644 index 5e4650c..0000000 --- a/include/muduo/base/WeakCallback.h +++ /dev/null @@ -1,65 +0,0 @@ -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef MUDUO_BASE_WEAKCALLBACK_H -#define MUDUO_BASE_WEAKCALLBACK_H - -#include -#include - -namespace muduo -{ - -// A barely usable WeakCallback - -template -class WeakCallback -{ - public: - - WeakCallback(const std::weak_ptr& object, - const std::function& function) - : object_(object), function_(function) - { - } - - // Default dtor, copy ctor and assignment are okay - - void operator()(ARGS&&... args) const - { - std::shared_ptr ptr(object_.lock()); - if (ptr) - { - function_(ptr.get(), std::forward(args)...); - } - // else - // { - // LOG_TRACE << "expired"; - // } - } - - private: - - std::weak_ptr object_; - std::function function_; -}; - -template -WeakCallback makeWeakCallback(const std::shared_ptr& object, - void (CLASS::*function)(ARGS...)) -{ - return WeakCallback(object, function); -} - -template -WeakCallback makeWeakCallback(const std::shared_ptr& object, - void (CLASS::*function)(ARGS...) const) -{ - return WeakCallback(object, function); -} - -} // namespace muduo - -#endif // MUDUO_BASE_WEAKCALLBACK_H diff --git a/include/muduo/base/copyable.h b/include/muduo/base/copyable.h deleted file mode 100644 index 352b287..0000000 --- a/include/muduo/base/copyable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MUDUO_BASE_COPYABLE_H -#define MUDUO_BASE_COPYABLE_H - -namespace muduo -{ - -/// A tag class emphasises the objects are copyable. -/// The empty base class optimization applies. -/// Any derived class of copyable should be a value type. -class copyable -{ - protected: - copyable() = default; - ~copyable() = default; -}; - -} // namespace muduo - -#endif // MUDUO_BASE_COPYABLE_H diff --git a/include/muduo/base/noncopyable.h b/include/muduo/base/noncopyable.h deleted file mode 100644 index 79931f9..0000000 --- a/include/muduo/base/noncopyable.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef MUDUO_BASE_NONCOPYABLE_H -#define MUDUO_BASE_NONCOPYABLE_H - -namespace muduo -{ - -class noncopyable -{ - public: - noncopyable(const noncopyable&) = delete; - void operator=(const noncopyable&) = delete; - - protected: - noncopyable() = default; - ~noncopyable() = default; -}; - -} // namespace muduo - -#endif // MUDUO_BASE_NONCOPYABLE_H diff --git a/include/muduo/base/tests/AsyncLogging_test.cc b/include/muduo/base/tests/AsyncLogging_test.cc deleted file mode 100644 index ad6fde4..0000000 --- a/include/muduo/base/tests/AsyncLogging_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -#include "muduo/base/AsyncLogging.h" -#include "muduo/base/Logging.h" -#include "muduo/base/Timestamp.h" - -#include -#include -#include - -off_t kRollSize = 500*1000*1000; - -muduo::AsyncLogging* g_asyncLog = NULL; - -void asyncOutput(const char* msg, int len) -{ - g_asyncLog->append(msg, len); -} - -void bench(bool longLog) -{ - muduo::Logger::setOutput(asyncOutput); - - int cnt = 0; - const int kBatch = 1000; - muduo::string empty = " "; - muduo::string longStr(3000, 'X'); - longStr += " "; - - for (int t = 0; t < 30; ++t) - { - muduo::Timestamp start = muduo::Timestamp::now(); - for (int i = 0; i < kBatch; ++i) - { - LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz " - << (longLog ? longStr : empty) - << cnt; - ++cnt; - } - muduo::Timestamp end = muduo::Timestamp::now(); - printf("%f\n", timeDifference(end, start)*1000000/kBatch); - struct timespec ts = { 0, 500*1000*1000 }; - nanosleep(&ts, NULL); - } -} - -int main(int argc, char* argv[]) -{ - { - // set max virtual memory to 2GB. - size_t kOneGB = 1000*1024*1024; - rlimit rl = { 2*kOneGB, 2*kOneGB }; - setrlimit(RLIMIT_AS, &rl); - } - - printf("pid = %d\n", getpid()); - - char name[256] = { '\0' }; - strncpy(name, argv[0], sizeof name - 1); - muduo::AsyncLogging log(::basename(name), kRollSize); - log.start(); - g_asyncLog = &log; - - bool longLog = argc > 1; - bench(longLog); -} diff --git a/include/muduo/base/tests/Atomic_unittest.cc b/include/muduo/base/tests/Atomic_unittest.cc deleted file mode 100644 index 11d6107..0000000 --- a/include/muduo/base/tests/Atomic_unittest.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include "muduo/base/Atomic.h" -#include - -int main() -{ - { - muduo::AtomicInt64 a0; - assert(a0.get() == 0); - assert(a0.getAndAdd(1) == 0); - assert(a0.get() == 1); - assert(a0.addAndGet(2) == 3); - assert(a0.get() == 3); - assert(a0.incrementAndGet() == 4); - assert(a0.get() == 4); - a0.increment(); - assert(a0.get() == 5); - assert(a0.addAndGet(-3) == 2); - assert(a0.getAndSet(100) == 2); - assert(a0.get() == 100); - } - - { - muduo::AtomicInt32 a1; - assert(a1.get() == 0); - assert(a1.getAndAdd(1) == 0); - assert(a1.get() == 1); - assert(a1.addAndGet(2) == 3); - assert(a1.get() == 3); - assert(a1.incrementAndGet() == 4); - assert(a1.get() == 4); - a1.increment(); - assert(a1.get() == 5); - assert(a1.addAndGet(-3) == 2); - assert(a1.getAndSet(100) == 2); - assert(a1.get() == 100); - } -} - diff --git a/include/muduo/base/tests/BlockingQueue_bench.cc b/include/muduo/base/tests/BlockingQueue_bench.cc deleted file mode 100644 index bd65bfa..0000000 --- a/include/muduo/base/tests/BlockingQueue_bench.cc +++ /dev/null @@ -1,106 +0,0 @@ -#include "muduo/base/BlockingQueue.h" -#include "muduo/base/CountDownLatch.h" -#include "muduo/base/Thread.h" -#include "muduo/base/Timestamp.h" - -#include -#include -#include -#include -#include - -class Bench -{ - public: - Bench(int numThreads) - : latch_(numThreads) - { - threads_.reserve(numThreads); - for (int i = 0; i < numThreads; ++i) - { - char name[32]; - snprintf(name, sizeof name, "work thread %d", i); - threads_.emplace_back(new muduo::Thread( - std::bind(&Bench::threadFunc, this), muduo::string(name))); - } - for (auto& thr : threads_) - { - thr->start(); - } - } - - void run(int times) - { - printf("waiting for count down latch\n"); - latch_.wait(); - printf("all threads started\n"); - for (int i = 0; i < times; ++i) - { - muduo::Timestamp now(muduo::Timestamp::now()); - queue_.put(now); - usleep(1000); - } - } - - void joinAll() - { - for (size_t i = 0; i < threads_.size(); ++i) - { - queue_.put(muduo::Timestamp::invalid()); - } - - for (auto& thr : threads_) - { - thr->join(); - } - } - - private: - - void threadFunc() - { - printf("tid=%d, %s started\n", - muduo::CurrentThread::tid(), - muduo::CurrentThread::name()); - - std::map delays; - latch_.countDown(); - bool running = true; - while (running) - { - muduo::Timestamp t(queue_.take()); - muduo::Timestamp now(muduo::Timestamp::now()); - if (t.valid()) - { - int delay = static_cast(timeDifference(now, t) * 1000000); - // printf("tid=%d, latency = %d us\n", - // muduo::CurrentThread::tid(), delay); - ++delays[delay]; - } - running = t.valid(); - } - - printf("tid=%d, %s stopped\n", - muduo::CurrentThread::tid(), - muduo::CurrentThread::name()); - for (const auto& delay : delays) - { - printf("tid = %d, delay = %d, count = %d\n", - muduo::CurrentThread::tid(), - delay.first, delay.second); - } - } - - muduo::BlockingQueue queue_; - muduo::CountDownLatch latch_; - std::vector> threads_; -}; - -int main(int argc, char* argv[]) -{ - int threads = argc > 1 ? atoi(argv[1]) : 1; - - Bench t(threads); - t.run(10000); - t.joinAll(); -} diff --git a/include/muduo/base/tests/BlockingQueue_test.cc b/include/muduo/base/tests/BlockingQueue_test.cc deleted file mode 100644 index 413fbd2..0000000 --- a/include/muduo/base/tests/BlockingQueue_test.cc +++ /dev/null @@ -1,106 +0,0 @@ -#include "muduo/base/BlockingQueue.h" -#include "muduo/base/CountDownLatch.h" -#include "muduo/base/Thread.h" - -#include -#include -#include -#include -#include - -class Test -{ - public: - Test(int numThreads) - : latch_(numThreads) - { - for (int i = 0; i < numThreads; ++i) - { - char name[32]; - snprintf(name, sizeof name, "work thread %d", i); - threads_.emplace_back(new muduo::Thread( - std::bind(&Test::threadFunc, this), muduo::string(name))); - } - for (auto& thr : threads_) - { - thr->start(); - } - } - - void run(int times) - { - printf("waiting for count down latch\n"); - latch_.wait(); - printf("all threads started\n"); - for (int i = 0; i < times; ++i) - { - char buf[32]; - snprintf(buf, sizeof buf, "hello %d", i); - queue_.put(buf); - printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); - } - } - - void joinAll() - { - for (size_t i = 0; i < threads_.size(); ++i) - { - queue_.put("stop"); - } - - for (auto& thr : threads_) - { - thr->join(); - } - } - - private: - - void threadFunc() - { - printf("tid=%d, %s started\n", - muduo::CurrentThread::tid(), - muduo::CurrentThread::name()); - - latch_.countDown(); - bool running = true; - while (running) - { - std::string d(queue_.take()); - printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); - running = (d != "stop"); - } - - printf("tid=%d, %s stopped\n", - muduo::CurrentThread::tid(), - muduo::CurrentThread::name()); - } - - muduo::BlockingQueue queue_; - muduo::CountDownLatch latch_; - std::vector> threads_; -}; - -void testMove() -{ - muduo::BlockingQueue> queue; - queue.put(std::unique_ptr(new int(42))); - std::unique_ptr x = queue.take(); - printf("took %d\n", *x); - *x = 123; - queue.put(std::move(x)); - std::unique_ptr y = queue.take(); - printf("took %d\n", *y); -} - -int main() -{ - printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); - Test t(5); - t.run(100); - t.joinAll(); - - testMove(); - - printf("number of created threads %d\n", muduo::Thread::numCreated()); -} diff --git a/include/muduo/base/tests/BoundedBlockingQueue_test.cc b/include/muduo/base/tests/BoundedBlockingQueue_test.cc deleted file mode 100644 index 49f57fb..0000000 --- a/include/muduo/base/tests/BoundedBlockingQueue_test.cc +++ /dev/null @@ -1,110 +0,0 @@ -#include "muduo/base/BoundedBlockingQueue.h" -#include "muduo/base/CountDownLatch.h" -#include "muduo/base/Thread.h" - -#include -#include - -#include -#include - -class Test -{ - public: - Test(int numThreads) - : queue_(20), - latch_(numThreads) - { - threads_.reserve(numThreads); - for (int i = 0; i < numThreads; ++i) - { - char name[32]; - snprintf(name, sizeof name, "work thread %d", i); - threads_.emplace_back(new muduo::Thread( - std::bind(&Test::threadFunc, this), muduo::string(name))); - } - for (auto& thr : threads_) - { - thr->start(); - } - } - - void run(int times) - { - printf("waiting for count down latch\n"); - latch_.wait(); - printf("all threads started\n"); - for (int i = 0; i < times; ++i) - { - char buf[32]; - snprintf(buf, sizeof buf, "hello %d", i); - queue_.put(buf); - printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); - } - } - - void joinAll() - { - for (size_t i = 0; i < threads_.size(); ++i) - { - queue_.put("stop"); - } - - for (auto& thr : threads_) - { - thr->join(); - } - } - - private: - - void threadFunc() - { - printf("tid=%d, %s started\n", - muduo::CurrentThread::tid(), - muduo::CurrentThread::name()); - - latch_.countDown(); - bool running = true; - while (running) - { - std::string d(queue_.take()); - printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); - running = (d != "stop"); - } - - printf("tid=%d, %s stopped\n", - muduo::CurrentThread::tid(), - muduo::CurrentThread::name()); - } - - muduo::BoundedBlockingQueue queue_; - muduo::CountDownLatch latch_; - std::vector> threads_; -}; - -void testMove() -{ -#if BOOST_VERSION >= 105500L - muduo::BoundedBlockingQueue> queue(10); - queue.put(std::unique_ptr(new int(42))); - std::unique_ptr x = queue.take(); - printf("took %d\n", *x); - *x = 123; - queue.put(std::move(x)); - std::unique_ptr y; - y = queue.take(); - printf("took %d\n", *y); -#endif -} - -int main() -{ - printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); - testMove(); - Test t(5); - t.run(100); - t.joinAll(); - - printf("number of created threads %d\n", muduo::Thread::numCreated()); -} diff --git a/include/muduo/base/tests/CMakeLists.txt b/include/muduo/base/tests/CMakeLists.txt deleted file mode 100644 index 01a1c7a..0000000 --- a/include/muduo/base/tests/CMakeLists.txt +++ /dev/null @@ -1,86 +0,0 @@ -add_executable(asynclogging_test AsyncLogging_test.cc) -target_link_libraries(asynclogging_test muduo_base) - -add_executable(atomic_unittest Atomic_unittest.cc) -add_test(NAME atomic_unittest COMMAND atomic_unittest) - -add_executable(blockingqueue_test BlockingQueue_test.cc) -target_link_libraries(blockingqueue_test muduo_base) - -add_executable(blockingqueue_bench BlockingQueue_bench.cc) -target_link_libraries(blockingqueue_bench muduo_base) - -add_executable(boundedblockingqueue_test BoundedBlockingQueue_test.cc) -target_link_libraries(boundedblockingqueue_test muduo_base) - -add_executable(date_unittest Date_unittest.cc) -target_link_libraries(date_unittest muduo_base) -add_test(NAME date_unittest COMMAND date_unittest) - -add_executable(exception_test Exception_test.cc) -target_link_libraries(exception_test muduo_base) -add_test(NAME exception_test COMMAND exception_test) - -add_executable(fileutil_test FileUtil_test.cc) -target_link_libraries(fileutil_test muduo_base) -add_test(NAME fileutil_test COMMAND fileutil_test) - -add_executable(fork_test Fork_test.cc) -target_link_libraries(fork_test muduo_base) - -if(ZLIB_FOUND) - add_executable(gzipfile_test GzipFile_test.cc) - target_link_libraries(gzipfile_test muduo_base z) - add_test(NAME gzipfile_test COMMAND gzipfile_test) -endif() - -add_executable(logfile_test LogFile_test.cc) -target_link_libraries(logfile_test muduo_base) - -add_executable(logging_test Logging_test.cc) -target_link_libraries(logging_test muduo_base) - -add_executable(logstream_bench LogStream_bench.cc) -target_link_libraries(logstream_bench muduo_base) - -if(BOOSTTEST_LIBRARY) -add_executable(logstream_test LogStream_test.cc) -target_link_libraries(logstream_test muduo_base boost_unit_test_framework) -add_test(NAME logstream_test COMMAND logstream_test) -endif() - -add_executable(mutex_test Mutex_test.cc) -target_link_libraries(mutex_test muduo_base) - -add_executable(processinfo_test ProcessInfo_test.cc) -target_link_libraries(processinfo_test muduo_base) - -add_executable(singleton_test Singleton_test.cc) -target_link_libraries(singleton_test muduo_base) - -add_executable(singleton_threadlocal_test SingletonThreadLocal_test.cc) -target_link_libraries(singleton_threadlocal_test muduo_base) - -add_executable(thread_bench Thread_bench.cc) -target_link_libraries(thread_bench muduo_base) - -add_executable(thread_test Thread_test.cc) -target_link_libraries(thread_test muduo_base) - -add_executable(threadlocal_test ThreadLocal_test.cc) -target_link_libraries(threadlocal_test muduo_base) - -add_executable(threadlocalsingleton_test ThreadLocalSingleton_test.cc) -target_link_libraries(threadlocalsingleton_test muduo_base) - -add_executable(threadpool_test ThreadPool_test.cc) -target_link_libraries(threadpool_test muduo_base) - -add_executable(timestamp_unittest Timestamp_unittest.cc) -target_link_libraries(timestamp_unittest muduo_base) -add_test(NAME timestamp_unittest COMMAND timestamp_unittest) - -add_executable(timezone_unittest TimeZone_unittest.cc) -target_link_libraries(timezone_unittest muduo_base) -add_test(NAME timezone_unittest COMMAND timezone_unittest) - diff --git a/include/muduo/base/tests/Date_unittest.cc b/include/muduo/base/tests/Date_unittest.cc deleted file mode 100644 index bf2d386..0000000 --- a/include/muduo/base/tests/Date_unittest.cc +++ /dev/null @@ -1,88 +0,0 @@ -#include "muduo/base/Date.h" -#include -#include - -using muduo::Date; - -const int kMonthsOfYear = 12; - -int isLeapYear(int year) -{ - if (year % 400 == 0) - return 1; - else if (year % 100 == 0) - return 0; - else if (year % 4 == 0) - return 1; - else - return 0; -} - -int daysOfMonth(int year, int month) -{ - static int days[2][kMonthsOfYear+1] = - { - { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - }; - return days[isLeapYear(year)][month]; -} - -void passByConstReference(const Date& x) -{ - printf("%s\n", x.toIsoString().c_str()); -} - -void passByValue(Date x) -{ - printf("%s\n", x.toIsoString().c_str()); -} - -int main() -{ - time_t now = time(NULL); - struct tm t1 = *gmtime(&now); - struct tm t2 = *localtime(&now); - Date someDay(2008, 9, 10); - printf("%s\n", someDay.toIsoString().c_str()); - passByValue(someDay); - passByConstReference(someDay); - Date todayUtc(t1); - printf("%s\n", todayUtc.toIsoString().c_str()); - Date todayLocal(t2); - printf("%s\n", todayLocal.toIsoString().c_str()); - - int julianDayNumber = 2415021; - int weekDay = 1; // Monday - - for (int year = 1900; year < 2500; ++year) - { - assert(Date(year, 3, 1).julianDayNumber() - Date(year, 2, 29).julianDayNumber() - == isLeapYear(year)); - for (int month = 1; month <= kMonthsOfYear; ++month) - { - for (int day = 1; day <= daysOfMonth(year, month); ++day) - { - Date d(year, month, day); - // printf("%s %d\n", d.toString().c_str(), d.weekDay()); - assert(year == d.year()); - assert(month == d.month()); - assert(day == d.day()); - assert(weekDay == d.weekDay()); - assert(julianDayNumber == d.julianDayNumber()); - - Date d2(julianDayNumber); - assert(year == d2.year()); - assert(month == d2.month()); - assert(day == d2.day()); - assert(weekDay == d2.weekDay()); - assert(julianDayNumber == d2.julianDayNumber()); - - ++julianDayNumber; - weekDay = (weekDay+1) % 7; - } - } - } - printf("All passed.\n"); -} - diff --git a/include/muduo/base/tests/Exception_test.cc b/include/muduo/base/tests/Exception_test.cc deleted file mode 100644 index 7fd8004..0000000 --- a/include/muduo/base/tests/Exception_test.cc +++ /dev/null @@ -1,51 +0,0 @@ -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Exception.h" -#include -#include -#include - -class Bar -{ - public: - void test(std::vector names = {}) - { - printf("Stack:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); - [] { - printf("Stack inside lambda:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); - }(); - std::function func([] { - printf("Stack inside std::function:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); - }); - func(); - - func = std::bind(&Bar::callback, this); - func(); - - throw muduo::Exception("oops"); - } - - private: - void callback() - { - printf("Stack inside std::bind:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); - } -}; - -void foo() -{ - Bar b; - b.test(); -} - -int main() -{ - try - { - foo(); - } - catch (const muduo::Exception& ex) - { - printf("reason: %s\n", ex.what()); - printf("stack trace:\n%s\n", ex.stackTrace()); - } -} diff --git a/include/muduo/base/tests/FileUtil_test.cc b/include/muduo/base/tests/FileUtil_test.cc deleted file mode 100644 index 9abe299..0000000 --- a/include/muduo/base/tests/FileUtil_test.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "muduo/base/FileUtil.h" - -#include -#define __STDC_FORMAT_MACROS -#include - -using namespace muduo; - -int main() -{ - string result; - int64_t size = 0; - int err = FileUtil::readFile("/proc/self", 1024, &result, &size); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); - err = FileUtil::readFile("/proc/self", 1024, &result, NULL); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); - err = FileUtil::readFile("/proc/self/cmdline", 1024, &result, &size); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); - err = FileUtil::readFile("/dev/null", 1024, &result, &size); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); - err = FileUtil::readFile("/dev/zero", 1024, &result, &size); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); - err = FileUtil::readFile("/notexist", 1024, &result, &size); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); - err = FileUtil::readFile("/dev/zero", 102400, &result, &size); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); - err = FileUtil::readFile("/dev/zero", 102400, &result, NULL); - printf("%d %zd %" PRIu64 "\n", err, result.size(), size); -} - diff --git a/include/muduo/base/tests/Fork_test.cc b/include/muduo/base/tests/Fork_test.cc deleted file mode 100644 index 6a3cba6..0000000 --- a/include/muduo/base/tests/Fork_test.cc +++ /dev/null @@ -1,46 +0,0 @@ -#include "muduo/base/CurrentThread.h" - -#include -#include -#include - -namespace -{ -__thread int x = 0; -} - -void print() -{ - printf("pid=%d tid=%d x=%d\n", getpid(), muduo::CurrentThread::tid(), x); -} - -int main() -{ - printf("parent %d\n", getpid()); - print(); - x = 1; - print(); - pid_t p = fork(); - - if (p == 0) - { - printf("chlid %d\n", getpid()); - // child - print(); - x = 2; - print(); - - if (fork() == 0) - { - printf("grandchlid %d\n", getpid()); - print(); - x = 3; - print(); - } - } - else - { - // parent - print(); - } -} diff --git a/include/muduo/base/tests/GzipFile_test.cc b/include/muduo/base/tests/GzipFile_test.cc deleted file mode 100644 index d3f9cc3..0000000 --- a/include/muduo/base/tests/GzipFile_test.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include "muduo/base/GzipFile.h" - -#include "muduo/base/Logging.h" - -int main() -{ - const char* filename = "/tmp/gzipfile_test.gz"; - ::unlink(filename); - const char data[] = "123456789012345678901234567890123456789012345678901234567890\n"; - { - muduo::GzipFile writer = muduo::GzipFile::openForAppend(filename); - if (writer.valid()) - { - LOG_INFO << "tell " << writer.tell(); - LOG_INFO << "wrote " << writer.write(data); - LOG_INFO << "tell " << writer.tell(); - } - } - - { - printf("testing reader\n"); - muduo::GzipFile reader = muduo::GzipFile::openForRead(filename); - if (reader.valid()) - { - char buf[256]; - LOG_INFO << "tell " << reader.tell(); - int nr = reader.read(buf, sizeof buf); - printf("read %d\n", nr); - if (nr >= 0) - { - buf[nr] = '\0'; - printf("data %s", buf); - } - LOG_INFO << "tell " << reader.tell(); - if (strncmp(buf, data, strlen(data)) != 0) - { - printf("failed!!!\n"); - abort(); - } - else - { - printf("PASSED\n"); - } - } - } - - { - muduo::GzipFile writer = muduo::GzipFile::openForWriteExclusive(filename); - if (writer.valid() || errno != EEXIST) - { - printf("FAILED\n"); - } - } -} diff --git a/include/muduo/base/tests/LogFile_test.cc b/include/muduo/base/tests/LogFile_test.cc deleted file mode 100644 index a0b753a..0000000 --- a/include/muduo/base/tests/LogFile_test.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include "muduo/base/LogFile.h" -#include "muduo/base/Logging.h" - -#include - -std::unique_ptr g_logFile; - -void outputFunc(const char* msg, int len) -{ - g_logFile->append(msg, len); -} - -void flushFunc() -{ - g_logFile->flush(); -} - -int main(int argc, char* argv[]) -{ - char name[256] = { '\0' }; - strncpy(name, argv[0], sizeof name - 1); - g_logFile.reset(new muduo::LogFile(::basename(name), 200*1000)); - muduo::Logger::setOutput(outputFunc); - muduo::Logger::setFlush(flushFunc); - - muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; - - for (int i = 0; i < 10000; ++i) - { - LOG_INFO << line << i; - - usleep(1000); - } -} diff --git a/include/muduo/base/tests/LogStream_bench.cc b/include/muduo/base/tests/LogStream_bench.cc deleted file mode 100644 index c91637a..0000000 --- a/include/muduo/base/tests/LogStream_bench.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include "muduo/base/LogStream.h" -#include "muduo/base/Timestamp.h" - -#include -#include -#define __STDC_FORMAT_MACROS -#include - -using namespace muduo; - -const size_t N = 1000000; - -#pragma GCC diagnostic ignored "-Wold-style-cast" - -template -void benchPrintf(const char* fmt) -{ - char buf[32]; - Timestamp start(Timestamp::now()); - for (size_t i = 0; i < N; ++i) - snprintf(buf, sizeof buf, fmt, (T)(i)); - Timestamp end(Timestamp::now()); - - printf("benchPrintf %f\n", timeDifference(end, start)); -} - -template -void benchStringStream() -{ - Timestamp start(Timestamp::now()); - std::ostringstream os; - - for (size_t i = 0; i < N; ++i) - { - os << (T)(i); - os.seekp(0, std::ios_base::beg); - } - Timestamp end(Timestamp::now()); - - printf("benchStringStream %f\n", timeDifference(end, start)); -} - -template -void benchLogStream() -{ - Timestamp start(Timestamp::now()); - LogStream os; - for (size_t i = 0; i < N; ++i) - { - os << (T)(i); - os.resetBuffer(); - } - Timestamp end(Timestamp::now()); - - printf("benchLogStream %f\n", timeDifference(end, start)); -} - -int main() -{ - benchPrintf("%d"); - - puts("int"); - benchPrintf("%d"); - benchStringStream(); - benchLogStream(); - - puts("double"); - benchPrintf("%.12g"); - benchStringStream(); - benchLogStream(); - - puts("int64_t"); - benchPrintf("%" PRId64); - benchStringStream(); - benchLogStream(); - - puts("void*"); - benchPrintf("%p"); - benchStringStream(); - benchLogStream(); - -} diff --git a/include/muduo/base/tests/LogStream_test.cc b/include/muduo/base/tests/LogStream_test.cc deleted file mode 100644 index b6070e1..0000000 --- a/include/muduo/base/tests/LogStream_test.cc +++ /dev/null @@ -1,286 +0,0 @@ -#include "muduo/base/LogStream.h" - -#include -#include - -//#define BOOST_TEST_MODULE LogStreamTest -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include - -using muduo::string; - -BOOST_AUTO_TEST_CASE(testLogStreamBooleans) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - BOOST_CHECK_EQUAL(buf.toString(), string("")); - os << true; - BOOST_CHECK_EQUAL(buf.toString(), string("1")); - os << '\n'; - BOOST_CHECK_EQUAL(buf.toString(), string("1\n")); - os << false; - BOOST_CHECK_EQUAL(buf.toString(), string("1\n0")); -} - -BOOST_AUTO_TEST_CASE(testLogStreamIntegers) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - BOOST_CHECK_EQUAL(buf.toString(), string("")); - os << 1; - BOOST_CHECK_EQUAL(buf.toString(), string("1")); - os << 0; - BOOST_CHECK_EQUAL(buf.toString(), string("10")); - os << -1; - BOOST_CHECK_EQUAL(buf.toString(), string("10-1")); - os.resetBuffer(); - - os << 0 << " " << 123 << 'x' << 0x64; - BOOST_CHECK_EQUAL(buf.toString(), string("0 123x100")); -} - -BOOST_AUTO_TEST_CASE(testLogStreamIntegerLimits) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - os << -2147483647; - BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647")); - os << static_cast(-2147483647 - 1); - BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648")); - os << ' '; - os << 2147483647; - BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648 2147483647")); - os.resetBuffer(); - - os << std::numeric_limits::min(); - BOOST_CHECK_EQUAL(buf.toString(), string("-32768")); - os.resetBuffer(); - - os << std::numeric_limits::max(); - BOOST_CHECK_EQUAL(buf.toString(), string("32767")); - os.resetBuffer(); - - os << std::numeric_limits::min(); - BOOST_CHECK_EQUAL(buf.toString(), string("0")); - os.resetBuffer(); - - os << std::numeric_limits::max(); - BOOST_CHECK_EQUAL(buf.toString(), string("65535")); - os.resetBuffer(); - - os << std::numeric_limits::min(); - BOOST_CHECK_EQUAL(buf.toString(), string("-2147483648")); - os.resetBuffer(); - - os << std::numeric_limits::max(); - BOOST_CHECK_EQUAL(buf.toString(), string("2147483647")); - os.resetBuffer(); - - os << std::numeric_limits::min(); - BOOST_CHECK_EQUAL(buf.toString(), string("0")); - os.resetBuffer(); - - os << std::numeric_limits::max(); - BOOST_CHECK_EQUAL(buf.toString(), string("4294967295")); - os.resetBuffer(); - - os << std::numeric_limits::min(); - BOOST_CHECK_EQUAL(buf.toString(), string("-9223372036854775808")); - os.resetBuffer(); - - os << std::numeric_limits::max(); - BOOST_CHECK_EQUAL(buf.toString(), string("9223372036854775807")); - os.resetBuffer(); - - os << std::numeric_limits::min(); - BOOST_CHECK_EQUAL(buf.toString(), string("0")); - os.resetBuffer(); - - os << std::numeric_limits::max(); - BOOST_CHECK_EQUAL(buf.toString(), string("18446744073709551615")); - os.resetBuffer(); - - int16_t a = 0; - int32_t b = 0; - int64_t c = 0; - os << a; - os << b; - os << c; - BOOST_CHECK_EQUAL(buf.toString(), string("000")); -} - -BOOST_AUTO_TEST_CASE(testLogStreamFloats) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - - os << 0.0; - BOOST_CHECK_EQUAL(buf.toString(), string("0")); - os.resetBuffer(); - - os << 1.0; - BOOST_CHECK_EQUAL(buf.toString(), string("1")); - os.resetBuffer(); - - os << 0.1; - BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); - os.resetBuffer(); - - os << 0.05; - BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); - os.resetBuffer(); - - os << 0.15; - BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); - os.resetBuffer(); - - double a = 0.1; - os << a; - BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); - os.resetBuffer(); - - double b = 0.05; - os << b; - BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); - os.resetBuffer(); - - double c = 0.15; - os << c; - BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); - os.resetBuffer(); - - os << a+b; - BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); - os.resetBuffer(); - - BOOST_CHECK(a+b != c); - - os << 1.23456789; - BOOST_CHECK_EQUAL(buf.toString(), string("1.23456789")); - os.resetBuffer(); - - os << 1.234567; - BOOST_CHECK_EQUAL(buf.toString(), string("1.234567")); - os.resetBuffer(); - - os << -123.456; - BOOST_CHECK_EQUAL(buf.toString(), string("-123.456")); - os.resetBuffer(); -} - -BOOST_AUTO_TEST_CASE(testLogStreamVoid) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - - os << static_cast(0); - BOOST_CHECK_EQUAL(buf.toString(), string("0x0")); - os.resetBuffer(); - - os << reinterpret_cast(8888); - BOOST_CHECK_EQUAL(buf.toString(), string("0x22B8")); - os.resetBuffer(); -} - -BOOST_AUTO_TEST_CASE(testLogStreamStrings) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - - os << "Hello "; - BOOST_CHECK_EQUAL(buf.toString(), string("Hello ")); - - string chenshuo = "Shuo Chen"; - os << chenshuo; - BOOST_CHECK_EQUAL(buf.toString(), string("Hello Shuo Chen")); -} - -BOOST_AUTO_TEST_CASE(testLogStreamFmts) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - - os << muduo::Fmt("%4d", 1); - BOOST_CHECK_EQUAL(buf.toString(), string(" 1")); - os.resetBuffer(); - - os << muduo::Fmt("%4.2f", 1.2); - BOOST_CHECK_EQUAL(buf.toString(), string("1.20")); - os.resetBuffer(); - - os << muduo::Fmt("%4.2f", 1.2) << muduo::Fmt("%4d", 43); - BOOST_CHECK_EQUAL(buf.toString(), string("1.20 43")); - os.resetBuffer(); -} - -BOOST_AUTO_TEST_CASE(testLogStreamLong) -{ - muduo::LogStream os; - const muduo::LogStream::Buffer& buf = os.buffer(); - for (int i = 0; i < 399; ++i) - { - os << "123456789 "; - BOOST_CHECK_EQUAL(buf.length(), 10*(i+1)); - BOOST_CHECK_EQUAL(buf.avail(), 4000 - 10*(i+1)); - } - - os << "abcdefghi "; - BOOST_CHECK_EQUAL(buf.length(), 3990); - BOOST_CHECK_EQUAL(buf.avail(), 10); - - os << "abcdefghi"; - BOOST_CHECK_EQUAL(buf.length(), 3999); - BOOST_CHECK_EQUAL(buf.avail(), 1); -} - -BOOST_AUTO_TEST_CASE(testFormatSI) -{ - BOOST_CHECK_EQUAL(muduo::formatSI(0), string("0")); - BOOST_CHECK_EQUAL(muduo::formatSI(999), string("999")); - BOOST_CHECK_EQUAL(muduo::formatSI(1000), string("1.00k")); - BOOST_CHECK_EQUAL(muduo::formatSI(9990), string("9.99k")); - BOOST_CHECK_EQUAL(muduo::formatSI(9994), string("9.99k")); - BOOST_CHECK_EQUAL(muduo::formatSI(9995), string("10.0k")); - BOOST_CHECK_EQUAL(muduo::formatSI(10000), string("10.0k")); - BOOST_CHECK_EQUAL(muduo::formatSI(10049), string("10.0k")); - BOOST_CHECK_EQUAL(muduo::formatSI(10050), string("10.1k")); - BOOST_CHECK_EQUAL(muduo::formatSI(99900), string("99.9k")); - BOOST_CHECK_EQUAL(muduo::formatSI(99949), string("99.9k")); - BOOST_CHECK_EQUAL(muduo::formatSI(99950), string("100k")); - BOOST_CHECK_EQUAL(muduo::formatSI(100499), string("100k")); - // FIXME: - // BOOST_CHECK_EQUAL(muduo::formatSI(100500), string("101k")); - BOOST_CHECK_EQUAL(muduo::formatSI(100501), string("101k")); - BOOST_CHECK_EQUAL(muduo::formatSI(999499), string("999k")); - BOOST_CHECK_EQUAL(muduo::formatSI(999500), string("1.00M")); - BOOST_CHECK_EQUAL(muduo::formatSI(1004999), string("1.00M")); - // BOOST_CHECK_EQUAL(muduo::formatSI(1005000), string("1.01M")); - BOOST_CHECK_EQUAL(muduo::formatSI(1005001), string("1.01M")); - BOOST_CHECK_EQUAL(muduo::formatSI(INT64_MAX), string("9.22E")); -} - -BOOST_AUTO_TEST_CASE(testFormatIEC) -{ - BOOST_CHECK_EQUAL(muduo::formatIEC(0), string("0")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1023), string("1023")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1024), string("1.00Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(10234), string("9.99Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(10235), string("10.0Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(10240), string("10.0Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(10291), string("10.0Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(10292), string("10.1Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(102348), string("99.9Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(102349), string("100Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(102912), string("100Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(102913), string("101Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1022976), string("999Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1047552), string("1023Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1047961), string("1023Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1048063), string("1023Ki")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1048064), string("1.00Mi")); - BOOST_CHECK_EQUAL(muduo::formatIEC(1048576), string("1.00Mi")); - BOOST_CHECK_EQUAL(muduo::formatIEC(10480517), string("9.99Mi")); - BOOST_CHECK_EQUAL(muduo::formatIEC(10480518), string("10.0Mi")); - BOOST_CHECK_EQUAL(muduo::formatIEC(INT64_MAX), string("8.00Ei")); -} diff --git a/include/muduo/base/tests/Logging_test.cc b/include/muduo/base/tests/Logging_test.cc deleted file mode 100644 index 3de5e86..0000000 --- a/include/muduo/base/tests/Logging_test.cc +++ /dev/null @@ -1,122 +0,0 @@ -#include "muduo/base/Logging.h" -#include "muduo/base/LogFile.h" -#include "muduo/base/ThreadPool.h" -#include "muduo/base/TimeZone.h" - -#include -#include - -int g_total; -FILE* g_file; -std::unique_ptr g_logFile; - -void dummyOutput(const char* msg, int len) -{ - g_total += len; - if (g_file) - { - fwrite(msg, 1, len, g_file); - } - else if (g_logFile) - { - g_logFile->append(msg, len); - } -} - -void bench(const char* type) -{ - muduo::Logger::setOutput(dummyOutput); - muduo::Timestamp start(muduo::Timestamp::now()); - g_total = 0; - - int n = 1000*1000; - const bool kLongLog = false; - muduo::string empty = " "; - muduo::string longStr(3000, 'X'); - longStr += " "; - for (int i = 0; i < n; ++i) - { - LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz" - << (kLongLog ? longStr : empty) - << i; - } - muduo::Timestamp end(muduo::Timestamp::now()); - double seconds = timeDifference(end, start); - printf("%12s: %f seconds, %d bytes, %10.2f msg/s, %.2f MiB/s\n", - type, seconds, g_total, n / seconds, g_total / seconds / (1024 * 1024)); -} - -void logInThread() -{ - LOG_INFO << "logInThread"; - usleep(1000); -} - -int main() -{ - getppid(); // for ltrace and strace - - muduo::ThreadPool pool("pool"); - pool.start(5); - pool.run(logInThread); - pool.run(logInThread); - pool.run(logInThread); - pool.run(logInThread); - pool.run(logInThread); - - LOG_TRACE << "trace"; - LOG_DEBUG << "debug"; - LOG_INFO << "Hello"; - LOG_WARN << "World"; - LOG_ERROR << "Error"; - LOG_INFO << sizeof(muduo::Logger); - LOG_INFO << sizeof(muduo::LogStream); - LOG_INFO << sizeof(muduo::Fmt); - LOG_INFO << sizeof(muduo::LogStream::Buffer); - - sleep(1); - bench("nop"); - - char buffer[64*1024]; - - g_file = fopen("/dev/null", "w"); - setbuffer(g_file, buffer, sizeof buffer); - bench("/dev/null"); - fclose(g_file); - - g_file = fopen("/tmp/log", "w"); - setbuffer(g_file, buffer, sizeof buffer); - bench("/tmp/log"); - fclose(g_file); - - g_file = NULL; - g_logFile.reset(new muduo::LogFile("test_log_st", 500*1000*1000, false)); - bench("test_log_st"); - - g_logFile.reset(new muduo::LogFile("test_log_mt", 500*1000*1000, true)); - bench("test_log_mt"); - g_logFile.reset(); - - { - g_file = stdout; - sleep(1); - muduo::TimeZone beijing(8*3600, "CST"); - muduo::Logger::setTimeZone(beijing); - LOG_TRACE << "trace CST"; - LOG_DEBUG << "debug CST"; - LOG_INFO << "Hello CST"; - LOG_WARN << "World CST"; - LOG_ERROR << "Error CST"; - - sleep(1); - muduo::TimeZone newyork("/usr/share/zoneinfo/America/New_York"); - muduo::Logger::setTimeZone(newyork); - LOG_TRACE << "trace NYT"; - LOG_DEBUG << "debug NYT"; - LOG_INFO << "Hello NYT"; - LOG_WARN << "World NYT"; - LOG_ERROR << "Error NYT"; - g_file = NULL; - } - bench("timezone nop"); -} diff --git a/include/muduo/base/tests/Mutex_test.cc b/include/muduo/base/tests/Mutex_test.cc deleted file mode 100644 index 0c22d71..0000000 --- a/include/muduo/base/tests/Mutex_test.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include "muduo/base/CountDownLatch.h" -#include "muduo/base/Mutex.h" -#include "muduo/base/Thread.h" -#include "muduo/base/Timestamp.h" - -#include -#include - -using namespace muduo; -using namespace std; - -MutexLock g_mutex; -vector g_vec; -const int kCount = 10*1000*1000; - -void threadFunc() -{ - for (int i = 0; i < kCount; ++i) - { - MutexLockGuard lock(g_mutex); - g_vec.push_back(i); - } -} - -int foo() __attribute__ ((noinline)); - -int g_count = 0; -int foo() -{ - MutexLockGuard lock(g_mutex); - if (!g_mutex.isLockedByThisThread()) - { - printf("FAIL\n"); - return -1; - } - - ++g_count; - return 0; -} - -int main() -{ - MCHECK(foo()); - if (g_count != 1) - { - printf("MCHECK calls twice.\n"); - abort(); - } - - const int kMaxThreads = 8; - g_vec.reserve(kMaxThreads * kCount); - - Timestamp start(Timestamp::now()); - for (int i = 0; i < kCount; ++i) - { - g_vec.push_back(i); - } - - printf("single thread without lock %f\n", timeDifference(Timestamp::now(), start)); - - start = Timestamp::now(); - threadFunc(); - printf("single thread with lock %f\n", timeDifference(Timestamp::now(), start)); - - for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads) - { - std::vector> threads; - g_vec.clear(); - start = Timestamp::now(); - for (int i = 0; i < nthreads; ++i) - { - threads.emplace_back(new Thread(&threadFunc)); - threads.back()->start(); - } - for (int i = 0; i < nthreads; ++i) - { - threads[i]->join(); - } - printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start)); - } -} - diff --git a/include/muduo/base/tests/ProcessInfo_test.cc b/include/muduo/base/tests/ProcessInfo_test.cc deleted file mode 100644 index 6e30bad..0000000 --- a/include/muduo/base/tests/ProcessInfo_test.cc +++ /dev/null @@ -1,17 +0,0 @@ -#include "muduo/base/ProcessInfo.h" -#include -#define __STDC_FORMAT_MACROS -#include - -int main() -{ - printf("pid = %d\n", muduo::ProcessInfo::pid()); - printf("uid = %d\n", muduo::ProcessInfo::uid()); - printf("euid = %d\n", muduo::ProcessInfo::euid()); - printf("start time = %s\n", muduo::ProcessInfo::startTime().toFormattedString().c_str()); - printf("hostname = %s\n", muduo::ProcessInfo::hostname().c_str()); - printf("opened files = %d\n", muduo::ProcessInfo::openedFiles()); - printf("threads = %zd\n", muduo::ProcessInfo::threads().size()); - printf("num threads = %d\n", muduo::ProcessInfo::numThreads()); - printf("status = %s\n", muduo::ProcessInfo::procStatus().c_str()); -} diff --git a/include/muduo/base/tests/SingletonThreadLocal_test.cc b/include/muduo/base/tests/SingletonThreadLocal_test.cc deleted file mode 100644 index 29edf6c..0000000 --- a/include/muduo/base/tests/SingletonThreadLocal_test.cc +++ /dev/null @@ -1,58 +0,0 @@ -#include "muduo/base/Singleton.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/ThreadLocal.h" -#include "muduo/base/Thread.h" - -#include -#include - -class Test : muduo::noncopyable -{ - public: - Test() - { - printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); - } - - ~Test() - { - printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); - } - - const muduo::string& name() const { return name_; } - void setName(const muduo::string& n) { name_ = n; } - - private: - muduo::string name_; -}; - -#define STL muduo::Singleton >::instance().value() - -void print() -{ - printf("tid=%d, %p name=%s\n", - muduo::CurrentThread::tid(), - &STL, - STL.name().c_str()); -} - -void threadFunc(const char* changeTo) -{ - print(); - STL.setName(changeTo); - sleep(1); - print(); -} - -int main() -{ - STL.setName("main one"); - muduo::Thread t1(std::bind(threadFunc, "thread1")); - muduo::Thread t2(std::bind(threadFunc, "thread2")); - t1.start(); - t2.start(); - t1.join(); - print(); - t2.join(); - pthread_exit(0); -} diff --git a/include/muduo/base/tests/Singleton_test.cc b/include/muduo/base/tests/Singleton_test.cc deleted file mode 100644 index 124d7f7..0000000 --- a/include/muduo/base/tests/Singleton_test.cc +++ /dev/null @@ -1,65 +0,0 @@ -#include "muduo/base/Singleton.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Thread.h" - -#include - -class Test : muduo::noncopyable -{ - public: - Test() - { - printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); - } - - ~Test() - { - printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); - } - - const muduo::string& name() const { return name_; } - void setName(const muduo::string& n) { name_ = n; } - - private: - muduo::string name_; -}; - -class TestNoDestroy : muduo::noncopyable -{ - public: - // Tag member for Singleton - void no_destroy(); - - TestNoDestroy() - { - printf("tid=%d, constructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); - } - - ~TestNoDestroy() - { - printf("tid=%d, destructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); - } -}; - -void threadFunc() -{ - printf("tid=%d, %p name=%s\n", - muduo::CurrentThread::tid(), - &muduo::Singleton::instance(), - muduo::Singleton::instance().name().c_str()); - muduo::Singleton::instance().setName("only one, changed"); -} - -int main() -{ - muduo::Singleton::instance().setName("only one"); - muduo::Thread t1(threadFunc); - t1.start(); - t1.join(); - printf("tid=%d, %p name=%s\n", - muduo::CurrentThread::tid(), - &muduo::Singleton::instance(), - muduo::Singleton::instance().name().c_str()); - muduo::Singleton::instance(); - printf("with valgrind, you should see %zd-byte memory leak.\n", sizeof(TestNoDestroy)); -} diff --git a/include/muduo/base/tests/ThreadLocalSingleton_test.cc b/include/muduo/base/tests/ThreadLocalSingleton_test.cc deleted file mode 100644 index efe485a..0000000 --- a/include/muduo/base/tests/ThreadLocalSingleton_test.cc +++ /dev/null @@ -1,58 +0,0 @@ -#include "muduo/base/ThreadLocalSingleton.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Thread.h" - -#include - -class Test : muduo::noncopyable -{ - public: - Test() - { - printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); - } - - ~Test() - { - printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); - } - - const muduo::string& name() const { return name_; } - void setName(const muduo::string& n) { name_ = n; } - - private: - muduo::string name_; -}; - -void threadFunc(const char* changeTo) -{ - printf("tid=%d, %p name=%s\n", - muduo::CurrentThread::tid(), - &muduo::ThreadLocalSingleton::instance(), - muduo::ThreadLocalSingleton::instance().name().c_str()); - muduo::ThreadLocalSingleton::instance().setName(changeTo); - printf("tid=%d, %p name=%s\n", - muduo::CurrentThread::tid(), - &muduo::ThreadLocalSingleton::instance(), - muduo::ThreadLocalSingleton::instance().name().c_str()); - - // no need to manually delete it - // muduo::ThreadLocalSingleton::destroy(); -} - -int main() -{ - muduo::ThreadLocalSingleton::instance().setName("main one"); - muduo::Thread t1(std::bind(threadFunc, "thread1")); - muduo::Thread t2(std::bind(threadFunc, "thread2")); - t1.start(); - t2.start(); - t1.join(); - printf("tid=%d, %p name=%s\n", - muduo::CurrentThread::tid(), - &muduo::ThreadLocalSingleton::instance(), - muduo::ThreadLocalSingleton::instance().name().c_str()); - t2.join(); - - pthread_exit(0); -} diff --git a/include/muduo/base/tests/ThreadLocal_test.cc b/include/muduo/base/tests/ThreadLocal_test.cc deleted file mode 100644 index a5b89cf..0000000 --- a/include/muduo/base/tests/ThreadLocal_test.cc +++ /dev/null @@ -1,61 +0,0 @@ -#include "muduo/base/ThreadLocal.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Thread.h" - -#include - -class Test : muduo::noncopyable -{ - public: - Test() - { - printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); - } - - ~Test() - { - printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); - } - - const muduo::string& name() const { return name_; } - void setName(const muduo::string& n) { name_ = n; } - - private: - muduo::string name_; -}; - -muduo::ThreadLocal testObj1; -muduo::ThreadLocal testObj2; - -void print() -{ - printf("tid=%d, obj1 %p name=%s\n", - muduo::CurrentThread::tid(), - &testObj1.value(), - testObj1.value().name().c_str()); - printf("tid=%d, obj2 %p name=%s\n", - muduo::CurrentThread::tid(), - &testObj2.value(), - testObj2.value().name().c_str()); -} - -void threadFunc() -{ - print(); - testObj1.value().setName("changed 1"); - testObj2.value().setName("changed 42"); - print(); -} - -int main() -{ - testObj1.value().setName("main one"); - print(); - muduo::Thread t1(threadFunc); - t1.start(); - t1.join(); - testObj2.value().setName("main two"); - print(); - - pthread_exit(0); -} diff --git a/include/muduo/base/tests/ThreadPool_test.cc b/include/muduo/base/tests/ThreadPool_test.cc deleted file mode 100644 index de0dd60..0000000 --- a/include/muduo/base/tests/ThreadPool_test.cc +++ /dev/null @@ -1,97 +0,0 @@ -#include "muduo/base/ThreadPool.h" -#include "muduo/base/CountDownLatch.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Logging.h" - -#include -#include // usleep - -void print() -{ - printf("tid=%d\n", muduo::CurrentThread::tid()); -} - -void printString(const std::string& str) -{ - LOG_INFO << str; - usleep(100*1000); -} - -void test(int maxSize) -{ - LOG_WARN << "Test ThreadPool with max queue size = " << maxSize; - muduo::ThreadPool pool("MainThreadPool"); - pool.setMaxQueueSize(maxSize); - pool.start(5); - - LOG_WARN << "Adding"; - pool.run(print); - pool.run(print); - for (int i = 0; i < 100; ++i) - { - char buf[32]; - snprintf(buf, sizeof buf, "task %d", i); - pool.run(std::bind(printString, std::string(buf))); - } - LOG_WARN << "Done"; - - muduo::CountDownLatch latch(1); - pool.run(std::bind(&muduo::CountDownLatch::countDown, &latch)); - latch.wait(); - pool.stop(); -} - -/* - * Wish we could do this in the future. -void testMove() -{ - muduo::ThreadPool pool; - pool.start(2); - - std::unique_ptr x(new int(42)); - pool.run([y = std::move(x)]{ printf("%d: %d\n", muduo::CurrentThread::tid(), *y); }); - pool.stop(); -} -*/ - -void longTask(int num) -{ - LOG_INFO << "longTask " << num; - muduo::CurrentThread::sleepUsec(3000000); -} - -void test2() -{ - LOG_WARN << "Test ThreadPool by stoping early."; - muduo::ThreadPool pool("ThreadPool"); - pool.setMaxQueueSize(5); - pool.start(3); - - muduo::Thread thread1([&pool]() - { - for (int i = 0; i < 20; ++i) - { - pool.run(std::bind(longTask, i)); - } - }, "thread1"); - thread1.start(); - - muduo::CurrentThread::sleepUsec(5000000); - LOG_WARN << "stop pool"; - pool.stop(); // early stop - - thread1.join(); - // run() after stop() - pool.run(print); - LOG_WARN << "test2 Done"; -} - -int main() -{ - test(0); - test(1); - test(5); - test(10); - test(50); - test2(); -} diff --git a/include/muduo/base/tests/Thread_bench.cc b/include/muduo/base/tests/Thread_bench.cc deleted file mode 100644 index ae3d49c..0000000 --- a/include/muduo/base/tests/Thread_bench.cc +++ /dev/null @@ -1,86 +0,0 @@ -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Mutex.h" -#include "muduo/base/Thread.h" -#include "muduo/base/Timestamp.h" - -#include -#include -#include -#include -#include - -muduo::MutexLock g_mutex; -std::map g_delays; - -void threadFunc() -{ - //printf("tid=%d\n", muduo::CurrentThread::tid()); -} - -void threadFunc2(muduo::Timestamp start) -{ - muduo::Timestamp now(muduo::Timestamp::now()); - int delay = static_cast(timeDifference(now, start) * 1000000); - muduo::MutexLockGuard lock(g_mutex); - ++g_delays[delay]; -} - -void forkBench() -{ - sleep(10); - muduo::Timestamp start(muduo::Timestamp::now()); - int kProcesses = 10*1000; - - for (int i = 0; i < kProcesses; ++i) - { - pid_t child = fork(); - if (child == 0) - { - exit(0); - } - else - { - waitpid(child, NULL, 0); - } - } - - double timeUsed = timeDifference(muduo::Timestamp::now(), start); - printf("process creation time used %f us\n", timeUsed*1000000/kProcesses); - printf("number of created processes %d\n", kProcesses); -} - -int main(int argc, char* argv[]) -{ - printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); - muduo::Timestamp start(muduo::Timestamp::now()); - - int kThreads = 100*1000; - for (int i = 0; i < kThreads; ++i) - { - muduo::Thread t1(threadFunc); - t1.start(); - t1.join(); - } - - double timeUsed = timeDifference(muduo::Timestamp::now(), start); - printf("thread creation time %f us\n", timeUsed*1000000/kThreads); - printf("number of created threads %d\n", muduo::Thread::numCreated()); - - for (int i = 0; i < kThreads; ++i) - { - muduo::Timestamp now(muduo::Timestamp::now()); - muduo::Thread t2(std::bind(threadFunc2, now)); - t2.start(); - t2.join(); - } - { - muduo::MutexLockGuard lock(g_mutex); - for (const auto& delay : g_delays) - { - printf("delay = %d, count = %d\n", - delay.first, delay.second); - } - } - - forkBench(); -} diff --git a/include/muduo/base/tests/Thread_test.cc b/include/muduo/base/tests/Thread_test.cc deleted file mode 100644 index d6e78b9..0000000 --- a/include/muduo/base/tests/Thread_test.cc +++ /dev/null @@ -1,91 +0,0 @@ -#include "muduo/base/Thread.h" -#include "muduo/base/CurrentThread.h" - -#include -#include -#include - -void mysleep(int seconds) -{ - timespec t = { seconds, 0 }; - nanosleep(&t, NULL); -} - -void threadFunc() -{ - printf("tid=%d\n", muduo::CurrentThread::tid()); -} - -void threadFunc2(int x) -{ - printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x); -} - -void threadFunc3() -{ - printf("tid=%d\n", muduo::CurrentThread::tid()); - mysleep(1); -} - -class Foo -{ - public: - explicit Foo(double x) - : x_(x) - { - } - - void memberFunc() - { - printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_); - } - - void memberFunc2(const std::string& text) - { - printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str()); - } - - private: - double x_; -}; - -int main() -{ - printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); - - muduo::Thread t1(threadFunc); - t1.start(); - printf("t1.tid=%d\n", t1.tid()); - t1.join(); - - muduo::Thread t2(std::bind(threadFunc2, 42), - "thread for free function with argument"); - t2.start(); - printf("t2.tid=%d\n", t2.tid()); - t2.join(); - - Foo foo(87.53); - muduo::Thread t3(std::bind(&Foo::memberFunc, &foo), - "thread for member function without argument"); - t3.start(); - t3.join(); - - muduo::Thread t4(std::bind(&Foo::memberFunc2, std::ref(foo), std::string("Shuo Chen"))); - t4.start(); - t4.join(); - - { - muduo::Thread t5(threadFunc3); - t5.start(); - // t5 may destruct eariler than thread creation. - } - mysleep(2); - { - muduo::Thread t6(threadFunc3); - t6.start(); - mysleep(2); - // t6 destruct later than thread creation. - } - sleep(2); - printf("number of created threads %d\n", muduo::Thread::numCreated()); -} diff --git a/include/muduo/base/tests/TimeZone_unittest.cc b/include/muduo/base/tests/TimeZone_unittest.cc deleted file mode 100644 index 5d1de82..0000000 --- a/include/muduo/base/tests/TimeZone_unittest.cc +++ /dev/null @@ -1,276 +0,0 @@ -#include "muduo/base/TimeZone.h" -#include "muduo/base/Types.h" - -#include -#include -#include - -using muduo::TimeZone; - -struct tm getTm(int year, int month, int day, - int hour, int minute, int seconds) -{ - struct tm gmt; - muduo::memZero(&gmt, sizeof gmt); - gmt.tm_year = year - 1900; - gmt.tm_mon = month - 1; - gmt.tm_mday = day; - gmt.tm_hour = hour; - gmt.tm_min = minute; - gmt.tm_sec = seconds; - return gmt; -} - -struct tm getTm(const char* str) -{ - struct tm gmt; - muduo::memZero(&gmt, sizeof gmt); - strptime(str, "%F %T", &gmt); - return gmt; -} - -time_t getGmt(int year, int month, int day, - int hour, int minute, int seconds) -{ - struct tm gmt = getTm(year, month, day, hour, minute, seconds); - return timegm(&gmt); -} - -time_t getGmt(const char* str) -{ - struct tm gmt = getTm(str); - return timegm(&gmt); -} - -struct TestCase -{ - const char* gmt; - const char* local; - bool isdst; -}; - -void test(const TimeZone& tz, TestCase tc) -{ - time_t gmt = getGmt(tc.gmt); - - { - struct tm local = tz.toLocalTime(gmt); - char buf[256]; - strftime(buf, sizeof buf, "%F %T%z(%Z)", &local); - - if (strcmp(buf, tc.local) != 0 || tc.isdst != local.tm_isdst) - { - printf("WRONG: "); - } - printf("%s -> %s\n", tc.gmt, buf); - } - - { - struct tm local = getTm(tc.local); - local.tm_isdst = tc.isdst; - time_t result = tz.fromLocalTime(local); - if (result != gmt) - { - struct tm local2 = tz.toLocalTime(result); - char buf[256]; - strftime(buf, sizeof buf, "%F %T%z(%Z)", &local2); - - printf("WRONG fromLocalTime: %ld %ld %s\n", - static_cast(gmt), static_cast(result), buf); - } - } -} - -void testNewYork() -{ - TimeZone tz("/usr/share/zoneinfo/America/New_York"); - TestCase cases[] = - { - - { "2006-03-07 00:00:00", "2006-03-06 19:00:00-0500(EST)", false }, - { "2006-04-02 06:59:59", "2006-04-02 01:59:59-0500(EST)", false }, - { "2006-04-02 07:00:00", "2006-04-02 03:00:00-0400(EDT)", true }, - { "2006-05-01 00:00:00", "2006-04-30 20:00:00-0400(EDT)", true }, - { "2006-05-02 01:00:00", "2006-05-01 21:00:00-0400(EDT)", true }, - { "2006-10-21 05:00:00", "2006-10-21 01:00:00-0400(EDT)", true }, - { "2006-10-29 05:59:59", "2006-10-29 01:59:59-0400(EDT)", true }, - { "2006-10-29 06:00:00", "2006-10-29 01:00:00-0500(EST)", false }, - { "2006-10-29 06:59:59", "2006-10-29 01:59:59-0500(EST)", false }, - { "2006-12-31 06:00:00", "2006-12-31 01:00:00-0500(EST)", false }, - { "2007-01-01 00:00:00", "2006-12-31 19:00:00-0500(EST)", false }, - - { "2007-03-07 00:00:00", "2007-03-06 19:00:00-0500(EST)", false }, - { "2007-03-11 06:59:59", "2007-03-11 01:59:59-0500(EST)", false }, - { "2007-03-11 07:00:00", "2007-03-11 03:00:00-0400(EDT)", true }, - { "2007-05-01 00:00:00", "2007-04-30 20:00:00-0400(EDT)", true }, - { "2007-05-02 01:00:00", "2007-05-01 21:00:00-0400(EDT)", true }, - { "2007-10-31 05:00:00", "2007-10-31 01:00:00-0400(EDT)", true }, - { "2007-11-04 05:59:59", "2007-11-04 01:59:59-0400(EDT)", true }, - { "2007-11-04 06:00:00", "2007-11-04 01:00:00-0500(EST)", false }, - { "2007-11-04 06:59:59", "2007-11-04 01:59:59-0500(EST)", false }, - { "2007-12-31 06:00:00", "2007-12-31 01:00:00-0500(EST)", false }, - { "2008-01-01 00:00:00", "2007-12-31 19:00:00-0500(EST)", false }, - - { "2009-03-07 00:00:00", "2009-03-06 19:00:00-0500(EST)", false }, - { "2009-03-08 06:59:59", "2009-03-08 01:59:59-0500(EST)", false }, - { "2009-03-08 07:00:00", "2009-03-08 03:00:00-0400(EDT)", true }, - { "2009-05-01 00:00:00", "2009-04-30 20:00:00-0400(EDT)", true }, - { "2009-05-02 01:00:00", "2009-05-01 21:00:00-0400(EDT)", true }, - { "2009-10-31 05:00:00", "2009-10-31 01:00:00-0400(EDT)", true }, - { "2009-11-01 05:59:59", "2009-11-01 01:59:59-0400(EDT)", true }, - { "2009-11-01 06:00:00", "2009-11-01 01:00:00-0500(EST)", false }, - { "2009-11-01 06:59:59", "2009-11-01 01:59:59-0500(EST)", false }, - { "2009-12-31 06:00:00", "2009-12-31 01:00:00-0500(EST)", false }, - { "2010-01-01 00:00:00", "2009-12-31 19:00:00-0500(EST)", false }, - - { "2010-03-13 00:00:00", "2010-03-12 19:00:00-0500(EST)", false }, - { "2010-03-14 06:59:59", "2010-03-14 01:59:59-0500(EST)", false }, - { "2010-03-14 07:00:00", "2010-03-14 03:00:00-0400(EDT)", true }, - { "2010-05-01 00:00:00", "2010-04-30 20:00:00-0400(EDT)", true }, - { "2010-05-02 01:00:00", "2010-05-01 21:00:00-0400(EDT)", true }, - { "2010-11-06 05:00:00", "2010-11-06 01:00:00-0400(EDT)", true }, - { "2010-11-07 05:59:59", "2010-11-07 01:59:59-0400(EDT)", true }, - { "2010-11-07 06:00:00", "2010-11-07 01:00:00-0500(EST)", false }, - { "2010-11-07 06:59:59", "2010-11-07 01:59:59-0500(EST)", false }, - { "2010-12-31 06:00:00", "2010-12-31 01:00:00-0500(EST)", false }, - { "2011-01-01 00:00:00", "2010-12-31 19:00:00-0500(EST)", false }, - - { "2011-03-01 00:00:00", "2011-02-28 19:00:00-0500(EST)", false }, - { "2011-03-13 06:59:59", "2011-03-13 01:59:59-0500(EST)", false }, - { "2011-03-13 07:00:00", "2011-03-13 03:00:00-0400(EDT)", true }, - { "2011-05-01 00:00:00", "2011-04-30 20:00:00-0400(EDT)", true }, - { "2011-05-02 01:00:00", "2011-05-01 21:00:00-0400(EDT)", true }, - { "2011-11-06 05:59:59", "2011-11-06 01:59:59-0400(EDT)", true }, - { "2011-11-06 06:00:00", "2011-11-06 01:00:00-0500(EST)", false }, - { "2011-11-06 06:59:59", "2011-11-06 01:59:59-0500(EST)", false }, - { "2011-12-31 06:00:00", "2011-12-31 01:00:00-0500(EST)", false }, - { "2012-01-01 00:00:00", "2011-12-31 19:00:00-0500(EST)", false }, - - }; - - for (const auto& c : cases) - { - test(tz, c); - } -} - -void testLondon() -{ - TimeZone tz("/usr/share/zoneinfo/Europe/London"); - TestCase cases[] = - { - - { "2011-03-26 00:00:00", "2011-03-26 00:00:00+0000(GMT)", false }, - { "2011-03-27 00:59:59", "2011-03-27 00:59:59+0000(GMT)", false }, - { "2011-03-27 01:00:00", "2011-03-27 02:00:00+0100(BST)", true }, - { "2011-10-30 00:59:59", "2011-10-30 01:59:59+0100(BST)", true }, - { "2011-10-30 01:00:00", "2011-10-30 01:00:00+0000(GMT)", false }, - { "2012-10-30 01:59:59", "2012-10-30 01:59:59+0000(GMT)", false }, - { "2011-12-31 22:00:00", "2011-12-31 22:00:00+0000(GMT)", false }, - { "2012-01-01 00:00:00", "2012-01-01 00:00:00+0000(GMT)", false }, - - { "2012-03-24 00:00:00", "2012-03-24 00:00:00+0000(GMT)", false }, - { "2012-03-25 00:59:59", "2012-03-25 00:59:59+0000(GMT)", false }, - { "2012-03-25 01:00:00", "2012-03-25 02:00:00+0100(BST)", true }, - { "2012-10-28 00:59:59", "2012-10-28 01:59:59+0100(BST)", true }, - { "2012-10-28 01:00:00", "2012-10-28 01:00:00+0000(GMT)", false }, - { "2012-10-28 01:59:59", "2012-10-28 01:59:59+0000(GMT)", false }, - { "2012-12-31 22:00:00", "2012-12-31 22:00:00+0000(GMT)", false }, - { "2013-01-01 00:00:00", "2013-01-01 00:00:00+0000(GMT)", false }, - - }; - - for (const auto& c : cases) - { - test(tz, c); - } -} - -void testHongKong() -{ - TimeZone tz("/usr/share/zoneinfo/Asia/Hong_Kong"); - TestCase cases[] = - { - - { "2011-04-03 00:00:00", "2011-04-03 08:00:00+0800(HKT)", false}, - - }; - - for (const auto& c : cases) - { - test(tz, c); - } -} - -void testSydney() -{ - TimeZone tz("/usr/share/zoneinfo/Australia/Sydney"); - TestCase cases[] = - { - - { "2011-01-01 00:00:00", "2011-01-01 11:00:00+1100(EST)", true }, - { "2011-04-02 15:59:59", "2011-04-03 02:59:59+1100(EST)", true }, - { "2011-04-02 16:00:00", "2011-04-03 02:00:00+1000(EST)", false }, - { "2011-04-02 16:59:59", "2011-04-03 02:59:59+1000(EST)", false }, - { "2011-05-02 01:00:00", "2011-05-02 11:00:00+1000(EST)", false }, - { "2011-10-01 15:59:59", "2011-10-02 01:59:59+1000(EST)", false }, - { "2011-10-01 16:00:00", "2011-10-02 03:00:00+1100(EST)", true }, - { "2011-12-31 22:00:00", "2012-01-01 09:00:00+1100(EST)", true }, - - }; - - for (const auto& c : cases) - { - test(tz, c); - } -} - -void testUtc() -{ - const int kRange = 100*1000*1000; - for (time_t t = -kRange; t <= kRange; t += 11) - { - struct tm* t1 = gmtime(&t); - struct tm t2 = TimeZone::toUtcTime(t, true); - char buf1[80], buf2[80]; - strftime(buf1, sizeof buf1, "%F %T %u %j", t1); - strftime(buf2, sizeof buf2, "%F %T %u %j", &t2); - if (strcmp(buf1, buf2) != 0) - { - printf("'%s' != '%s'\n", buf1, buf2); - assert(0); - } - time_t t3 = TimeZone::fromUtcTime(t2); - if (t != t3) - { - printf("%ld != %ld\n", static_cast(t), static_cast(t3)); - assert(0); - } - } -} - -void testFixedTimezone() -{ - TimeZone tz(8*3600, "CST"); - TestCase cases[] = - { - - { "2014-04-03 00:00:00", "2014-04-03 08:00:00+0800(CST)", false}, - - }; - - for (const auto& c : cases) - { - test(tz, c); - } -} - -int main() -{ - testNewYork(); - testLondon(); - testSydney(); - testHongKong(); - testFixedTimezone(); - testUtc(); -} diff --git a/include/muduo/base/tests/Timestamp_unittest.cc b/include/muduo/base/tests/Timestamp_unittest.cc deleted file mode 100644 index 5e27592..0000000 --- a/include/muduo/base/tests/Timestamp_unittest.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include "muduo/base/Timestamp.h" -#include -#include - -using muduo::Timestamp; - -void passByConstReference(const Timestamp& x) -{ - printf("%s\n", x.toString().c_str()); -} - -void passByValue(Timestamp x) -{ - printf("%s\n", x.toString().c_str()); -} - -void benchmark() -{ - const int kNumber = 1000*1000; - - std::vector stamps; - stamps.reserve(kNumber); - for (int i = 0; i < kNumber; ++i) - { - stamps.push_back(Timestamp::now()); - } - printf("%s\n", stamps.front().toString().c_str()); - printf("%s\n", stamps.back().toString().c_str()); - printf("%f\n", timeDifference(stamps.back(), stamps.front())); - - int increments[100] = { 0 }; - int64_t start = stamps.front().microSecondsSinceEpoch(); - for (int i = 1; i < kNumber; ++i) - { - int64_t next = stamps[i].microSecondsSinceEpoch(); - int64_t inc = next - start; - start = next; - if (inc < 0) - { - printf("reverse!\n"); - } - else if (inc < 100) - { - ++increments[inc]; - } - else - { - printf("big gap %d\n", static_cast(inc)); - } - } - - for (int i = 0; i < 100; ++i) - { - printf("%2d: %d\n", i, increments[i]); - } -} - -int main() -{ - Timestamp now(Timestamp::now()); - printf("%s\n", now.toString().c_str()); - passByValue(now); - passByConstReference(now); - benchmark(); -} - diff --git a/include/muduo/net/Acceptor.cc b/include/muduo/net/Acceptor.cc deleted file mode 100644 index 39d0cb6..0000000 --- a/include/muduo/net/Acceptor.cc +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/Acceptor.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/InetAddress.h" -#include "muduo/net/SocketsOps.h" - -#include -#include -//#include -//#include -#include - -using namespace muduo; -using namespace muduo::net; - -Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) - : loop_(loop), - acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), - acceptChannel_(loop, acceptSocket_.fd()), - listening_(false), - idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) -{ - assert(idleFd_ >= 0); - acceptSocket_.setReuseAddr(true); - acceptSocket_.setReusePort(reuseport); - acceptSocket_.bindAddress(listenAddr); - acceptChannel_.setReadCallback( - std::bind(&Acceptor::handleRead, this)); -} - -Acceptor::~Acceptor() -{ - acceptChannel_.disableAll(); - acceptChannel_.remove(); - ::close(idleFd_); -} - -void Acceptor::listen() -{ - loop_->assertInLoopThread(); - listening_ = true; - acceptSocket_.listen(); - acceptChannel_.enableReading(); -} - -void Acceptor::handleRead() -{ - loop_->assertInLoopThread(); - InetAddress peerAddr; - //FIXME loop until no more - int connfd = acceptSocket_.accept(&peerAddr); - if (connfd >= 0) - { - // string hostport = peerAddr.toIpPort(); - // LOG_TRACE << "Accepts of " << hostport; - if (newConnectionCallback_) - { - newConnectionCallback_(connfd, peerAddr); - } - else - { - sockets::close(connfd); - } - } - else - { - LOG_SYSERR << "in Acceptor::handleRead"; - // Read the section named "The special problem of - // accept()ing when you can't" in libev's doc. - // By Marc Lehmann, author of libev. - if (errno == EMFILE) - { - ::close(idleFd_); - idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); - ::close(idleFd_); - idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); - } - } -} - diff --git a/include/muduo/net/Acceptor.h b/include/muduo/net/Acceptor.h deleted file mode 100644 index 761d073..0000000 --- a/include/muduo/net/Acceptor.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_ACCEPTOR_H -#define MUDUO_NET_ACCEPTOR_H - -#include - -#include "muduo/net/Channel.h" -#include "muduo/net/Socket.h" - -namespace muduo -{ -namespace net -{ - -class EventLoop; -class InetAddress; - -/// -/// Acceptor of incoming TCP connections. -/// -class Acceptor : noncopyable -{ - public: - typedef std::function NewConnectionCallback; - - Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); - ~Acceptor(); - - void setNewConnectionCallback(const NewConnectionCallback& cb) - { newConnectionCallback_ = cb; } - - void listen(); - - bool listening() const { return listening_; } - - // Deprecated, use the correct spelling one above. - // Leave the wrong spelling here in case one needs to grep it for error messages. - // bool listenning() const { return listening(); } - - private: - void handleRead(); - - EventLoop* loop_; - Socket acceptSocket_; - Channel acceptChannel_; - NewConnectionCallback newConnectionCallback_; - bool listening_; - int idleFd_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_ACCEPTOR_H diff --git a/include/muduo/net/BUILD.bazel b/include/muduo/net/BUILD.bazel deleted file mode 100644 index 33d78d1..0000000 --- a/include/muduo/net/BUILD.bazel +++ /dev/null @@ -1,51 +0,0 @@ -cc_library( - name = "net", - srcs = [ - "Acceptor.cc", - "Buffer.cc", - "Channel.cc", - "Connector.cc", - "EventLoop.cc", - "EventLoopThread.cc", - "EventLoopThreadPool.cc", - "InetAddress.cc", - "Poller.cc", - "Socket.cc", - "SocketsOps.cc", - "TcpClient.cc", - "TcpConnection.cc", - "TcpServer.cc", - "Timer.cc", - "TimerQueue.cc", - "poller/DefaultPoller.cc", - "poller/EPollPoller.cc", - "poller/PollPoller.cc", - ], - hdrs = [ - "Acceptor.h", - "Buffer.h", - "Callbacks.h", - "Channel.h", - "Connector.h", - "Endian.h", - "EventLoop.h", - "EventLoopThread.h", - "EventLoopThreadPool.h", - "InetAddress.h", - "Poller.h", - "Socket.h", - "SocketsOps.h", - "TcpClient.h", - "TcpConnection.h", - "TcpServer.h", - "Timer.h", - "TimerId.h", - "TimerQueue.h", - "poller/EPollPoller.h", - "poller/PollPoller.h", - ], - visibility = ["//visibility:public"], - deps = [ - "//muduo/base", - ], -) diff --git a/include/muduo/net/Buffer.cc b/include/muduo/net/Buffer.cc deleted file mode 100644 index 7c921fc..0000000 --- a/include/muduo/net/Buffer.cc +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/Buffer.h" - -#include "muduo/net/SocketsOps.h" - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -const char Buffer::kCRLF[] = "\r\n"; - -const size_t Buffer::kCheapPrepend; -const size_t Buffer::kInitialSize; - -ssize_t Buffer::readFd(int fd, int* savedErrno) -{ - // saved an ioctl()/FIONREAD call to tell how much to read - char extrabuf[65536]; - struct iovec vec[2]; - const size_t writable = writableBytes(); - vec[0].iov_base = begin()+writerIndex_; - vec[0].iov_len = writable; - vec[1].iov_base = extrabuf; - vec[1].iov_len = sizeof extrabuf; - // when there is enough space in this buffer, don't read into extrabuf. - // when extrabuf is used, we read 128k-1 bytes at most. - const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; - const ssize_t n = sockets::readv(fd, vec, iovcnt); - if (n < 0) - { - *savedErrno = errno; - } - else if (implicit_cast(n) <= writable) - { - writerIndex_ += n; - } - else - { - writerIndex_ = buffer_.size(); - append(extrabuf, n - writable); - } - // if (n == writable + sizeof extrabuf) - // { - // goto line_30; - // } - return n; -} - diff --git a/include/muduo/net/Buffer.h b/include/muduo/net/Buffer.h deleted file mode 100644 index 4fa82d4..0000000 --- a/include/muduo/net/Buffer.h +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_BUFFER_H -#define MUDUO_NET_BUFFER_H - -#include "muduo/base/copyable.h" -#include "muduo/base/StringPiece.h" -#include "muduo/base/Types.h" - -#include "muduo/net/Endian.h" - -#include -#include - -#include -#include -//#include // ssize_t - -namespace muduo -{ -namespace net -{ - -/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer -/// -/// @code -/// +-------------------+------------------+------------------+ -/// | prependable bytes | readable bytes | writable bytes | -/// | | (CONTENT) | | -/// +-------------------+------------------+------------------+ -/// | | | | -/// 0 <= readerIndex <= writerIndex <= size -/// @endcode -class Buffer : public muduo::copyable -{ - public: - static const size_t kCheapPrepend = 8; - static const size_t kInitialSize = 1024; - - explicit Buffer(size_t initialSize = kInitialSize) - : buffer_(kCheapPrepend + initialSize), - readerIndex_(kCheapPrepend), - writerIndex_(kCheapPrepend) - { - assert(readableBytes() == 0); - assert(writableBytes() == initialSize); - assert(prependableBytes() == kCheapPrepend); - } - - // implicit copy-ctor, move-ctor, dtor and assignment are fine - // NOTE: implicit move-ctor is added in g++ 4.6 - - void swap(Buffer& rhs) - { - buffer_.swap(rhs.buffer_); - std::swap(readerIndex_, rhs.readerIndex_); - std::swap(writerIndex_, rhs.writerIndex_); - } - - size_t readableBytes() const - { return writerIndex_ - readerIndex_; } - - size_t writableBytes() const - { return buffer_.size() - writerIndex_; } - - size_t prependableBytes() const - { return readerIndex_; } - - const char* peek() const - { return begin() + readerIndex_; } - - const char* findCRLF() const - { - // FIXME: replace with memmem()? - const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2); - return crlf == beginWrite() ? NULL : crlf; - } - - const char* findCRLF(const char* start) const - { - assert(peek() <= start); - assert(start <= beginWrite()); - // FIXME: replace with memmem()? - const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2); - return crlf == beginWrite() ? NULL : crlf; - } - - const char* findEOL() const - { - const void* eol = memchr(peek(), '\n', readableBytes()); - return static_cast(eol); - } - - const char* findEOL(const char* start) const - { - assert(peek() <= start); - assert(start <= beginWrite()); - const void* eol = memchr(start, '\n', beginWrite() - start); - return static_cast(eol); - } - - // retrieve returns void, to prevent - // string str(retrieve(readableBytes()), readableBytes()); - // the evaluation of two functions are unspecified - void retrieve(size_t len) - { - assert(len <= readableBytes()); - if (len < readableBytes()) - { - readerIndex_ += len; - } - else - { - retrieveAll(); - } - } - - void retrieveUntil(const char* end) - { - assert(peek() <= end); - assert(end <= beginWrite()); - retrieve(end - peek()); - } - - void retrieveInt64() - { - retrieve(sizeof(int64_t)); - } - - void retrieveInt32() - { - retrieve(sizeof(int32_t)); - } - - void retrieveInt16() - { - retrieve(sizeof(int16_t)); - } - - void retrieveInt8() - { - retrieve(sizeof(int8_t)); - } - - void retrieveAll() - { - readerIndex_ = kCheapPrepend; - writerIndex_ = kCheapPrepend; - } - - string retrieveAllAsString() - { - return retrieveAsString(readableBytes()); - } - - string retrieveAsString(size_t len) - { - assert(len <= readableBytes()); - string result(peek(), len); - retrieve(len); - return result; - } - - StringPiece toStringPiece() const - { - return StringPiece(peek(), static_cast(readableBytes())); - } - - void append(const StringPiece& str) - { - append(str.data(), str.size()); - } - - void append(const char* /*restrict*/ data, size_t len) - { - ensureWritableBytes(len); - std::copy(data, data+len, beginWrite()); - hasWritten(len); - } - - void append(const void* /*restrict*/ data, size_t len) - { - append(static_cast(data), len); - } - - void ensureWritableBytes(size_t len) - { - if (writableBytes() < len) - { - makeSpace(len); - } - assert(writableBytes() >= len); - } - - char* beginWrite() - { return begin() + writerIndex_; } - - const char* beginWrite() const - { return begin() + writerIndex_; } - - void hasWritten(size_t len) - { - assert(len <= writableBytes()); - writerIndex_ += len; - } - - void unwrite(size_t len) - { - assert(len <= readableBytes()); - writerIndex_ -= len; - } - - /// - /// Append int64_t using network endian - /// - void appendInt64(int64_t x) - { - int64_t be64 = sockets::hostToNetwork64(x); - append(&be64, sizeof be64); - } - - /// - /// Append int32_t using network endian - /// - void appendInt32(int32_t x) - { - int32_t be32 = sockets::hostToNetwork32(x); - append(&be32, sizeof be32); - } - - void appendInt16(int16_t x) - { - int16_t be16 = sockets::hostToNetwork16(x); - append(&be16, sizeof be16); - } - - void appendInt8(int8_t x) - { - append(&x, sizeof x); - } - - /// - /// Read int64_t from network endian - /// - /// Require: buf->readableBytes() >= sizeof(int32_t) - int64_t readInt64() - { - int64_t result = peekInt64(); - retrieveInt64(); - return result; - } - - /// - /// Read int32_t from network endian - /// - /// Require: buf->readableBytes() >= sizeof(int32_t) - int32_t readInt32() - { - int32_t result = peekInt32(); - retrieveInt32(); - return result; - } - - int16_t readInt16() - { - int16_t result = peekInt16(); - retrieveInt16(); - return result; - } - - int8_t readInt8() - { - int8_t result = peekInt8(); - retrieveInt8(); - return result; - } - - /// - /// Peek int64_t from network endian - /// - /// Require: buf->readableBytes() >= sizeof(int64_t) - int64_t peekInt64() const - { - assert(readableBytes() >= sizeof(int64_t)); - int64_t be64 = 0; - ::memcpy(&be64, peek(), sizeof be64); - return sockets::networkToHost64(be64); - } - - /// - /// Peek int32_t from network endian - /// - /// Require: buf->readableBytes() >= sizeof(int32_t) - int32_t peekInt32() const - { - assert(readableBytes() >= sizeof(int32_t)); - int32_t be32 = 0; - ::memcpy(&be32, peek(), sizeof be32); - return sockets::networkToHost32(be32); - } - - int16_t peekInt16() const - { - assert(readableBytes() >= sizeof(int16_t)); - int16_t be16 = 0; - ::memcpy(&be16, peek(), sizeof be16); - return sockets::networkToHost16(be16); - } - - int8_t peekInt8() const - { - assert(readableBytes() >= sizeof(int8_t)); - int8_t x = *peek(); - return x; - } - - /// - /// Prepend int64_t using network endian - /// - void prependInt64(int64_t x) - { - int64_t be64 = sockets::hostToNetwork64(x); - prepend(&be64, sizeof be64); - } - - /// - /// Prepend int32_t using network endian - /// - void prependInt32(int32_t x) - { - int32_t be32 = sockets::hostToNetwork32(x); - prepend(&be32, sizeof be32); - } - - void prependInt16(int16_t x) - { - int16_t be16 = sockets::hostToNetwork16(x); - prepend(&be16, sizeof be16); - } - - void prependInt8(int8_t x) - { - prepend(&x, sizeof x); - } - - void prepend(const void* /*restrict*/ data, size_t len) - { - assert(len <= prependableBytes()); - readerIndex_ -= len; - const char* d = static_cast(data); - std::copy(d, d+len, begin()+readerIndex_); - } - - void shrink(size_t reserve) - { - // FIXME: use vector::shrink_to_fit() in C++ 11 if possible. - Buffer other; - other.ensureWritableBytes(readableBytes()+reserve); - other.append(toStringPiece()); - swap(other); - } - - size_t internalCapacity() const - { - return buffer_.capacity(); - } - - /// Read data directly into buffer. - /// - /// It may implement with readv(2) - /// @return result of read(2), @c errno is saved - ssize_t readFd(int fd, int* savedErrno); - - private: - - char* begin() - { return &*buffer_.begin(); } - - const char* begin() const - { return &*buffer_.begin(); } - - void makeSpace(size_t len) - { - if (writableBytes() + prependableBytes() < len + kCheapPrepend) - { - // FIXME: move readable data - buffer_.resize(writerIndex_+len); - } - else - { - // move readable data to the front, make space inside buffer - assert(kCheapPrepend < readerIndex_); - size_t readable = readableBytes(); - std::copy(begin()+readerIndex_, - begin()+writerIndex_, - begin()+kCheapPrepend); - readerIndex_ = kCheapPrepend; - writerIndex_ = readerIndex_ + readable; - assert(readable == readableBytes()); - } - } - - private: - std::vector buffer_; - size_t readerIndex_; - size_t writerIndex_; - - static const char kCRLF[]; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_BUFFER_H diff --git a/include/muduo/net/CMakeLists.txt b/include/muduo/net/CMakeLists.txt deleted file mode 100644 index 7510d87..0000000 --- a/include/muduo/net/CMakeLists.txt +++ /dev/null @@ -1,69 +0,0 @@ -include(CheckFunctionExists) - -check_function_exists(accept4 HAVE_ACCEPT4) -if(NOT HAVE_ACCEPT4) - set_source_files_properties(SocketsOps.cc PROPERTIES COMPILE_FLAGS "-DNO_ACCEPT4") -endif() - -set(net_SRCS - Acceptor.cc - Buffer.cc - Channel.cc - Connector.cc - EventLoop.cc - EventLoopThread.cc - EventLoopThreadPool.cc - InetAddress.cc - Poller.cc - poller/DefaultPoller.cc - poller/EPollPoller.cc - poller/PollPoller.cc - Socket.cc - SocketsOps.cc - TcpClient.cc - TcpConnection.cc - TcpServer.cc - Timer.cc - TimerQueue.cc - ) - -add_library(muduo_net ${net_SRCS}) -target_link_libraries(muduo_net muduo_base) - -#add_library(muduo_net_cpp11 ${net_SRCS}) -#target_link_libraries(muduo_net_cpp11 muduo_base_cpp11) -#set_target_properties(muduo_net_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") - -install(TARGETS muduo_net DESTINATION lib) -#install(TARGETS muduo_net_cpp11 DESTINATION lib) - -set(HEADERS - Buffer.h - Callbacks.h - Channel.h - Endian.h - EventLoop.h - EventLoopThread.h - EventLoopThreadPool.h - InetAddress.h - TcpClient.h - TcpConnection.h - TcpServer.h - TimerId.h - ) -install(FILES ${HEADERS} DESTINATION include/muduo/net) - -add_subdirectory(http) -add_subdirectory(inspect) - -if(MUDUO_BUILD_EXAMPLES) - add_subdirectory(tests) -endif() - -if(PROTOBUF_FOUND) - add_subdirectory(protobuf) - add_subdirectory(protorpc) -else() - add_subdirectory(protobuf EXCLUDE_FROM_ALL) - add_subdirectory(protorpc EXCLUDE_FROM_ALL) -endif() diff --git a/include/muduo/net/Callbacks.h b/include/muduo/net/Callbacks.h deleted file mode 100644 index 443ed79..0000000 --- a/include/muduo/net/Callbacks.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_CALLBACKS_H -#define MUDUO_NET_CALLBACKS_H - -#include "muduo/base/Timestamp.h" - -#include -#include - -namespace muduo -{ - -using std::placeholders::_1; -using std::placeholders::_2; -using std::placeholders::_3; - -// should really belong to base/Types.h, but is not included there. - -template -inline T* get_pointer(const std::shared_ptr& ptr) -{ - return ptr.get(); -} - -template -inline T* get_pointer(const std::unique_ptr& ptr) -{ - return ptr.get(); -} - -// Adapted from google-protobuf stubs/common.h -// see License in muduo/base/Types.h -template -inline ::std::shared_ptr down_pointer_cast(const ::std::shared_ptr& f) { - if (false) - { - implicit_cast(0); - } - -#ifndef NDEBUG - assert(f == NULL || dynamic_cast(get_pointer(f)) != NULL); -#endif - return ::std::static_pointer_cast(f); -} - -namespace net -{ - -// All client visible callbacks go here. - -class Buffer; -class TcpConnection; -typedef std::shared_ptr TcpConnectionPtr; -typedef std::function TimerCallback; -typedef std::function ConnectionCallback; -typedef std::function CloseCallback; -typedef std::function WriteCompleteCallback; -typedef std::function HighWaterMarkCallback; - -// the data has been read to (buf, len) -typedef std::function MessageCallback; - -void defaultConnectionCallback(const TcpConnectionPtr& conn); -void defaultMessageCallback(const TcpConnectionPtr& conn, - Buffer* buffer, - Timestamp receiveTime); - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_CALLBACKS_H diff --git a/include/muduo/net/Channel.cc b/include/muduo/net/Channel.cc deleted file mode 100644 index 1e9a40a..0000000 --- a/include/muduo/net/Channel.cc +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/base/Logging.h" -#include "muduo/net/Channel.h" -#include "muduo/net/EventLoop.h" - -#include - -#include - -using namespace muduo; -using namespace muduo::net; - -const int Channel::kNoneEvent = 0; -const int Channel::kReadEvent = POLLIN | POLLPRI; -const int Channel::kWriteEvent = POLLOUT; - -Channel::Channel(EventLoop* loop, int fd__) - : loop_(loop), - fd_(fd__), - events_(0), - revents_(0), - index_(-1), - logHup_(true), - tied_(false), - eventHandling_(false), - addedToLoop_(false) -{ -} - -Channel::~Channel() -{ - assert(!eventHandling_); - assert(!addedToLoop_); - if (loop_->isInLoopThread()) - { - assert(!loop_->hasChannel(this)); - } -} - -void Channel::tie(const std::shared_ptr& obj) -{ - tie_ = obj; - tied_ = true; -} - -void Channel::update() -{ - addedToLoop_ = true; - loop_->updateChannel(this); -} - -void Channel::remove() -{ - assert(isNoneEvent()); - addedToLoop_ = false; - loop_->removeChannel(this); -} - -void Channel::handleEvent(Timestamp receiveTime) -{ - std::shared_ptr guard; - if (tied_) - { - guard = tie_.lock(); - if (guard) - { - handleEventWithGuard(receiveTime); - } - } - else - { - handleEventWithGuard(receiveTime); - } -} - -void Channel::handleEventWithGuard(Timestamp receiveTime) -{ - eventHandling_ = true; - LOG_TRACE << reventsToString(); - if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) - { - if (logHup_) - { - LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP"; - } - if (closeCallback_) closeCallback_(); - } - - if (revents_ & POLLNVAL) - { - LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL"; - } - - if (revents_ & (POLLERR | POLLNVAL)) - { - if (errorCallback_) errorCallback_(); - } - if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) - { - if (readCallback_) readCallback_(receiveTime); - } - if (revents_ & POLLOUT) - { - if (writeCallback_) writeCallback_(); - } - eventHandling_ = false; -} - -string Channel::reventsToString() const -{ - return eventsToString(fd_, revents_); -} - -string Channel::eventsToString() const -{ - return eventsToString(fd_, events_); -} - -string Channel::eventsToString(int fd, int ev) -{ - std::ostringstream oss; - oss << fd << ": "; - if (ev & POLLIN) - oss << "IN "; - if (ev & POLLPRI) - oss << "PRI "; - if (ev & POLLOUT) - oss << "OUT "; - if (ev & POLLHUP) - oss << "HUP "; - if (ev & POLLRDHUP) - oss << "RDHUP "; - if (ev & POLLERR) - oss << "ERR "; - if (ev & POLLNVAL) - oss << "NVAL "; - - return oss.str(); -} diff --git a/include/muduo/net/Channel.h b/include/muduo/net/Channel.h deleted file mode 100644 index bafa224..0000000 --- a/include/muduo/net/Channel.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_CHANNEL_H -#define MUDUO_NET_CHANNEL_H - -#include "muduo/base/noncopyable.h" -#include "muduo/base/Timestamp.h" - -#include -#include - -namespace muduo -{ -namespace net -{ - -class EventLoop; - -/// -/// A selectable I/O channel. -/// -/// This class doesn't own the file descriptor. -/// The file descriptor could be a socket, -/// an eventfd, a timerfd, or a signalfd -class Channel : noncopyable -{ - public: - typedef std::function EventCallback; - typedef std::function ReadEventCallback; - - Channel(EventLoop* loop, int fd); - ~Channel(); - - void handleEvent(Timestamp receiveTime); - void setReadCallback(ReadEventCallback cb) - { readCallback_ = std::move(cb); } - void setWriteCallback(EventCallback cb) - { writeCallback_ = std::move(cb); } - void setCloseCallback(EventCallback cb) - { closeCallback_ = std::move(cb); } - void setErrorCallback(EventCallback cb) - { errorCallback_ = std::move(cb); } - - /// Tie this channel to the owner object managed by shared_ptr, - /// prevent the owner object being destroyed in handleEvent. - void tie(const std::shared_ptr&); - - int fd() const { return fd_; } - int events() const { return events_; } - void set_revents(int revt) { revents_ = revt; } // used by pollers - // int revents() const { return revents_; } - bool isNoneEvent() const { return events_ == kNoneEvent; } - - void enableReading() { events_ |= kReadEvent; update(); } - void disableReading() { events_ &= ~kReadEvent; update(); } - void enableWriting() { events_ |= kWriteEvent; update(); } - void disableWriting() { events_ &= ~kWriteEvent; update(); } - void disableAll() { events_ = kNoneEvent; update(); } - bool isWriting() const { return events_ & kWriteEvent; } - bool isReading() const { return events_ & kReadEvent; } - - // for Poller - int index() { return index_; } - void set_index(int idx) { index_ = idx; } - - // for debug - string reventsToString() const; - string eventsToString() const; - - void doNotLogHup() { logHup_ = false; } - - EventLoop* ownerLoop() { return loop_; } - void remove(); - - private: - static string eventsToString(int fd, int ev); - - void update(); - void handleEventWithGuard(Timestamp receiveTime); - - static const int kNoneEvent; - static const int kReadEvent; - static const int kWriteEvent; - - EventLoop* loop_; - const int fd_; - int events_; - int revents_; // it's the received event types of epoll or poll - int index_; // used by Poller. - bool logHup_; - - std::weak_ptr tie_; - bool tied_; - bool eventHandling_; - bool addedToLoop_; - ReadEventCallback readCallback_; - EventCallback writeCallback_; - EventCallback closeCallback_; - EventCallback errorCallback_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_CHANNEL_H diff --git a/include/muduo/net/Connector.cc b/include/muduo/net/Connector.cc deleted file mode 100644 index 0b492ad..0000000 --- a/include/muduo/net/Connector.cc +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/Connector.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/Channel.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/SocketsOps.h" - -#include - -using namespace muduo; -using namespace muduo::net; - -const int Connector::kMaxRetryDelayMs; - -Connector::Connector(EventLoop* loop, const InetAddress& serverAddr) - : loop_(loop), - serverAddr_(serverAddr), - connect_(false), - state_(kDisconnected), - retryDelayMs_(kInitRetryDelayMs) -{ - LOG_DEBUG << "ctor[" << this << "]"; -} - -Connector::~Connector() -{ - LOG_DEBUG << "dtor[" << this << "]"; - assert(!channel_); -} - -void Connector::start() -{ - connect_ = true; - loop_->runInLoop(std::bind(&Connector::startInLoop, this)); // FIXME: unsafe -} - -void Connector::startInLoop() -{ - loop_->assertInLoopThread(); - assert(state_ == kDisconnected); - if (connect_) - { - connect(); - } - else - { - LOG_DEBUG << "do not connect"; - } -} - -void Connector::stop() -{ - connect_ = false; - loop_->queueInLoop(std::bind(&Connector::stopInLoop, this)); // FIXME: unsafe - // FIXME: cancel timer -} - -void Connector::stopInLoop() -{ - loop_->assertInLoopThread(); - if (state_ == kConnecting) - { - setState(kDisconnected); - int sockfd = removeAndResetChannel(); - retry(sockfd); - } -} - -void Connector::connect() -{ - int sockfd = sockets::createNonblockingOrDie(serverAddr_.family()); - int ret = sockets::connect(sockfd, serverAddr_.getSockAddr()); - int savedErrno = (ret == 0) ? 0 : errno; - switch (savedErrno) - { - case 0: - case EINPROGRESS: - case EINTR: - case EISCONN: - connecting(sockfd); - break; - - case EAGAIN: - case EADDRINUSE: - case EADDRNOTAVAIL: - case ECONNREFUSED: - case ENETUNREACH: - retry(sockfd); - break; - - case EACCES: - case EPERM: - case EAFNOSUPPORT: - case EALREADY: - case EBADF: - case EFAULT: - case ENOTSOCK: - LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno; - sockets::close(sockfd); - break; - - default: - LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno; - sockets::close(sockfd); - // connectErrorCallback_(); - break; - } -} - -void Connector::restart() -{ - loop_->assertInLoopThread(); - setState(kDisconnected); - retryDelayMs_ = kInitRetryDelayMs; - connect_ = true; - startInLoop(); -} - -void Connector::connecting(int sockfd) -{ - setState(kConnecting); - assert(!channel_); - channel_.reset(new Channel(loop_, sockfd)); - channel_->setWriteCallback( - std::bind(&Connector::handleWrite, this)); // FIXME: unsafe - channel_->setErrorCallback( - std::bind(&Connector::handleError, this)); // FIXME: unsafe - - // channel_->tie(shared_from_this()); is not working, - // as channel_ is not managed by shared_ptr - channel_->enableWriting(); -} - -int Connector::removeAndResetChannel() -{ - channel_->disableAll(); - channel_->remove(); - int sockfd = channel_->fd(); - // Can't reset channel_ here, because we are inside Channel::handleEvent - loop_->queueInLoop(std::bind(&Connector::resetChannel, this)); // FIXME: unsafe - return sockfd; -} - -void Connector::resetChannel() -{ - channel_.reset(); -} - -void Connector::handleWrite() -{ - LOG_TRACE << "Connector::handleWrite " << state_; - - if (state_ == kConnecting) - { - int sockfd = removeAndResetChannel(); - int err = sockets::getSocketError(sockfd); - if (err) - { - LOG_WARN << "Connector::handleWrite - SO_ERROR = " - << err << " " << strerror_tl(err); - retry(sockfd); - } - else if (sockets::isSelfConnect(sockfd)) - { - LOG_WARN << "Connector::handleWrite - Self connect"; - retry(sockfd); - } - else - { - setState(kConnected); - if (connect_) - { - newConnectionCallback_(sockfd); - } - else - { - sockets::close(sockfd); - } - } - } - else - { - // what happened? - assert(state_ == kDisconnected); - } -} - -void Connector::handleError() -{ - LOG_ERROR << "Connector::handleError state=" << state_; - if (state_ == kConnecting) - { - int sockfd = removeAndResetChannel(); - int err = sockets::getSocketError(sockfd); - LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err); - retry(sockfd); - } -} - -void Connector::retry(int sockfd) -{ - sockets::close(sockfd); - setState(kDisconnected); - if (connect_) - { - LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toIpPort() - << " in " << retryDelayMs_ << " milliseconds. "; - loop_->runAfter(retryDelayMs_/1000.0, - std::bind(&Connector::startInLoop, shared_from_this())); - retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs); - } - else - { - LOG_DEBUG << "do not connect"; - } -} - diff --git a/include/muduo/net/Connector.h b/include/muduo/net/Connector.h deleted file mode 100644 index 4b79fb2..0000000 --- a/include/muduo/net/Connector.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_CONNECTOR_H -#define MUDUO_NET_CONNECTOR_H - -#include "muduo/base/noncopyable.h" -#include "muduo/net/InetAddress.h" - -#include -#include - -namespace muduo -{ -namespace net -{ - -class Channel; -class EventLoop; - -class Connector : noncopyable, - public std::enable_shared_from_this -{ - public: - typedef std::function NewConnectionCallback; - - Connector(EventLoop* loop, const InetAddress& serverAddr); - ~Connector(); - - void setNewConnectionCallback(const NewConnectionCallback& cb) - { newConnectionCallback_ = cb; } - - void start(); // can be called in any thread - void restart(); // must be called in loop thread - void stop(); // can be called in any thread - - const InetAddress& serverAddress() const { return serverAddr_; } - - private: - enum States { kDisconnected, kConnecting, kConnected }; - static const int kMaxRetryDelayMs = 30*1000; - static const int kInitRetryDelayMs = 500; - - void setState(States s) { state_ = s; } - void startInLoop(); - void stopInLoop(); - void connect(); - void connecting(int sockfd); - void handleWrite(); - void handleError(); - void retry(int sockfd); - int removeAndResetChannel(); - void resetChannel(); - - EventLoop* loop_; - InetAddress serverAddr_; - bool connect_; // atomic - States state_; // FIXME: use atomic variable - std::unique_ptr channel_; - NewConnectionCallback newConnectionCallback_; - int retryDelayMs_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_CONNECTOR_H diff --git a/include/muduo/net/Endian.h b/include/muduo/net/Endian.h deleted file mode 100644 index 82bd730..0000000 --- a/include/muduo/net/Endian.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_ENDIAN_H -#define MUDUO_NET_ENDIAN_H - -#include -#include - -namespace muduo -{ -namespace net -{ -namespace sockets -{ - -// the inline assembler code makes type blur, -// so we disable warnings for a while. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wold-style-cast" -inline uint64_t hostToNetwork64(uint64_t host64) -{ - return htobe64(host64); -} - -inline uint32_t hostToNetwork32(uint32_t host32) -{ - return htobe32(host32); -} - -inline uint16_t hostToNetwork16(uint16_t host16) -{ - return htobe16(host16); -} - -inline uint64_t networkToHost64(uint64_t net64) -{ - return be64toh(net64); -} - -inline uint32_t networkToHost32(uint32_t net32) -{ - return be32toh(net32); -} - -inline uint16_t networkToHost16(uint16_t net16) -{ - return be16toh(net16); -} - -#pragma GCC diagnostic pop - -} // namespace sockets -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_ENDIAN_H diff --git a/include/muduo/net/EventLoop.cc b/include/muduo/net/EventLoop.cc deleted file mode 100644 index b3feebe..0000000 --- a/include/muduo/net/EventLoop.cc +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/EventLoop.h" - -#include "muduo/base/Logging.h" -#include "muduo/base/Mutex.h" -#include "muduo/net/Channel.h" -#include "muduo/net/Poller.h" -#include "muduo/net/SocketsOps.h" -#include "muduo/net/TimerQueue.h" - -#include - -#include -#include -#include - -using namespace muduo; -using namespace muduo::net; - -namespace -{ -__thread EventLoop* t_loopInThisThread = 0; - -const int kPollTimeMs = 10000; - -int createEventfd() -{ - int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); - if (evtfd < 0) - { - LOG_SYSERR << "Failed in eventfd"; - abort(); - } - return evtfd; -} - -#pragma GCC diagnostic ignored "-Wold-style-cast" -class IgnoreSigPipe -{ - public: - IgnoreSigPipe() - { - ::signal(SIGPIPE, SIG_IGN); - // LOG_TRACE << "Ignore SIGPIPE"; - } -}; -#pragma GCC diagnostic error "-Wold-style-cast" - -IgnoreSigPipe initObj; -} // namespace - -EventLoop* EventLoop::getEventLoopOfCurrentThread() -{ - return t_loopInThisThread; -} - -EventLoop::EventLoop() - : looping_(false), - quit_(false), - eventHandling_(false), - callingPendingFunctors_(false), - iteration_(0), - threadId_(CurrentThread::tid()), - poller_(Poller::newDefaultPoller(this)), - timerQueue_(new TimerQueue(this)), - wakeupFd_(createEventfd()), - wakeupChannel_(new Channel(this, wakeupFd_)), - currentActiveChannel_(NULL) -{ - LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_; - if (t_loopInThisThread) - { - LOG_FATAL << "Another EventLoop " << t_loopInThisThread - << " exists in this thread " << threadId_; - } - else - { - t_loopInThisThread = this; - } - wakeupChannel_->setReadCallback( - std::bind(&EventLoop::handleRead, this)); - // we are always reading the wakeupfd - wakeupChannel_->enableReading(); -} - -EventLoop::~EventLoop() -{ - LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_ - << " destructs in thread " << CurrentThread::tid(); - wakeupChannel_->disableAll(); - wakeupChannel_->remove(); - ::close(wakeupFd_); - t_loopInThisThread = NULL; -} - -void EventLoop::loop() -{ - assert(!looping_); - assertInLoopThread(); - looping_ = true; - quit_ = false; // FIXME: what if someone calls quit() before loop() ? - LOG_TRACE << "EventLoop " << this << " start looping"; - - while (!quit_) - { - activeChannels_.clear(); - pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); - ++iteration_; - if (Logger::logLevel() <= Logger::TRACE) - { - printActiveChannels(); - } - // TODO sort channel by priority - eventHandling_ = true; - for (Channel* channel : activeChannels_) - { - currentActiveChannel_ = channel; - currentActiveChannel_->handleEvent(pollReturnTime_); - } - currentActiveChannel_ = NULL; - eventHandling_ = false; - doPendingFunctors(); - } - - LOG_TRACE << "EventLoop " << this << " stop looping"; - looping_ = false; -} - -void EventLoop::quit() -{ - quit_ = true; - // There is a chance that loop() just executes while(!quit_) and exits, - // then EventLoop destructs, then we are accessing an invalid object. - // Can be fixed using mutex_ in both places. - if (!isInLoopThread()) - { - wakeup(); - } -} - -void EventLoop::runInLoop(Functor cb) -{ - if (isInLoopThread()) - { - cb(); - } - else - { - queueInLoop(std::move(cb)); - } -} - -void EventLoop::queueInLoop(Functor cb) -{ - { - MutexLockGuard lock(mutex_); - pendingFunctors_.push_back(std::move(cb)); - } - - if (!isInLoopThread() || callingPendingFunctors_) - { - wakeup(); - } -} - -size_t EventLoop::queueSize() const -{ - MutexLockGuard lock(mutex_); - return pendingFunctors_.size(); -} - -TimerId EventLoop::runAt(Timestamp time, TimerCallback cb) -{ - return timerQueue_->addTimer(std::move(cb), time, 0.0); -} - -TimerId EventLoop::runAfter(double delay, TimerCallback cb) -{ - Timestamp time(addTime(Timestamp::now(), delay)); - return runAt(time, std::move(cb)); -} - -TimerId EventLoop::runEvery(double interval, TimerCallback cb) -{ - Timestamp time(addTime(Timestamp::now(), interval)); - return timerQueue_->addTimer(std::move(cb), time, interval); -} - -void EventLoop::cancel(TimerId timerId) -{ - return timerQueue_->cancel(timerId); -} - -void EventLoop::updateChannel(Channel* channel) -{ - assert(channel->ownerLoop() == this); - assertInLoopThread(); - poller_->updateChannel(channel); -} - -void EventLoop::removeChannel(Channel* channel) -{ - assert(channel->ownerLoop() == this); - assertInLoopThread(); - if (eventHandling_) - { - assert(currentActiveChannel_ == channel || - std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end()); - } - poller_->removeChannel(channel); -} - -bool EventLoop::hasChannel(Channel* channel) -{ - assert(channel->ownerLoop() == this); - assertInLoopThread(); - return poller_->hasChannel(channel); -} - -void EventLoop::abortNotInLoopThread() -{ - LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this - << " was created in threadId_ = " << threadId_ - << ", current thread id = " << CurrentThread::tid(); -} - -void EventLoop::wakeup() -{ - uint64_t one = 1; - ssize_t n = sockets::write(wakeupFd_, &one, sizeof one); - if (n != sizeof one) - { - LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8"; - } -} - -void EventLoop::handleRead() -{ - uint64_t one = 1; - ssize_t n = sockets::read(wakeupFd_, &one, sizeof one); - if (n != sizeof one) - { - LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8"; - } -} - -void EventLoop::doPendingFunctors() -{ - std::vector functors; - callingPendingFunctors_ = true; - - { - MutexLockGuard lock(mutex_); - functors.swap(pendingFunctors_); - } - - for (const Functor& functor : functors) - { - functor(); - } - callingPendingFunctors_ = false; -} - -void EventLoop::printActiveChannels() const -{ - for (const Channel* channel : activeChannels_) - { - LOG_TRACE << "{" << channel->reventsToString() << "} "; - } -} - diff --git a/include/muduo/net/EventLoop.h b/include/muduo/net/EventLoop.h deleted file mode 100644 index c2c53d3..0000000 --- a/include/muduo/net/EventLoop.h +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_EVENTLOOP_H -#define MUDUO_NET_EVENTLOOP_H - -#include -#include -#include - -#include - -#include "muduo/base/Mutex.h" -#include "muduo/base/CurrentThread.h" -#include "muduo/base/Timestamp.h" -#include "muduo/net/Callbacks.h" -#include "muduo/net/TimerId.h" - -namespace muduo -{ -namespace net -{ - -class Channel; -class Poller; -class TimerQueue; - -/// -/// Reactor, at most one per thread. -/// -/// This is an interface class, so don't expose too much details. -class EventLoop : noncopyable -{ - public: - typedef std::function Functor; - - EventLoop(); - ~EventLoop(); // force out-line dtor, for std::unique_ptr members. - - /// - /// Loops forever. - /// - /// Must be called in the same thread as creation of the object. - /// - void loop(); - - /// Quits loop. - /// - /// This is not 100% thread safe, if you call through a raw pointer, - /// better to call through shared_ptr for 100% safety. - void quit(); - - /// - /// Time when poll returns, usually means data arrival. - /// - Timestamp pollReturnTime() const { return pollReturnTime_; } - - int64_t iteration() const { return iteration_; } - - /// Runs callback immediately in the loop thread. - /// It wakes up the loop, and run the cb. - /// If in the same loop thread, cb is run within the function. - /// Safe to call from other threads. - void runInLoop(Functor cb); - /// Queues callback in the loop thread. - /// Runs after finish pooling. - /// Safe to call from other threads. - void queueInLoop(Functor cb); - - size_t queueSize() const; - - // timers - - /// - /// Runs callback at 'time'. - /// Safe to call from other threads. - /// - TimerId runAt(Timestamp time, TimerCallback cb); - /// - /// Runs callback after @c delay seconds. - /// Safe to call from other threads. - /// - TimerId runAfter(double delay, TimerCallback cb); - /// - /// Runs callback every @c interval seconds. - /// Safe to call from other threads. - /// - TimerId runEvery(double interval, TimerCallback cb); - /// - /// Cancels the timer. - /// Safe to call from other threads. - /// - void cancel(TimerId timerId); - - // internal usage - void wakeup(); - void updateChannel(Channel* channel); - void removeChannel(Channel* channel); - bool hasChannel(Channel* channel); - - // pid_t threadId() const { return threadId_; } - void assertInLoopThread() - { - if (!isInLoopThread()) - { - abortNotInLoopThread(); - } - } - bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } - // bool callingPendingFunctors() const { return callingPendingFunctors_; } - bool eventHandling() const { return eventHandling_; } - - void setContext(const boost::any& context) - { context_ = context; } - - const boost::any& getContext() const - { return context_; } - - boost::any* getMutableContext() - { return &context_; } - - static EventLoop* getEventLoopOfCurrentThread(); - - private: - void abortNotInLoopThread(); - void handleRead(); // waked up - void doPendingFunctors(); - - void printActiveChannels() const; // DEBUG - - typedef std::vector ChannelList; - - bool looping_; /* atomic */ - std::atomic quit_; - bool eventHandling_; /* atomic */ - bool callingPendingFunctors_; /* atomic */ - int64_t iteration_; - const pid_t threadId_; - Timestamp pollReturnTime_; - std::unique_ptr poller_; - std::unique_ptr timerQueue_; - int wakeupFd_; - // unlike in TimerQueue, which is an internal class, - // we don't expose Channel to client. - std::unique_ptr wakeupChannel_; - boost::any context_; - - // scratch variables - ChannelList activeChannels_; - Channel* currentActiveChannel_; - - mutable MutexLock mutex_; - std::vector pendingFunctors_ GUARDED_BY(mutex_); -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_EVENTLOOP_H diff --git a/include/muduo/net/EventLoopThread.cc b/include/muduo/net/EventLoopThread.cc deleted file mode 100644 index c1b6fa5..0000000 --- a/include/muduo/net/EventLoopThread.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/EventLoopThread.h" - -#include "muduo/net/EventLoop.h" - -using namespace muduo; -using namespace muduo::net; - -EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, - const string& name) - : loop_(NULL), - exiting_(false), - thread_(std::bind(&EventLoopThread::threadFunc, this), name), - mutex_(), - cond_(mutex_), - callback_(cb) -{ -} - -EventLoopThread::~EventLoopThread() -{ - exiting_ = true; - if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_. - { - // still a tiny chance to call destructed object, if threadFunc exits just now. - // but when EventLoopThread destructs, usually programming is exiting anyway. - loop_->quit(); - thread_.join(); - } -} - -EventLoop* EventLoopThread::startLoop() -{ - assert(!thread_.started()); - thread_.start(); - - EventLoop* loop = NULL; - { - MutexLockGuard lock(mutex_); - while (loop_ == NULL) - { - cond_.wait(); - } - loop = loop_; - } - - return loop; -} - -void EventLoopThread::threadFunc() -{ - EventLoop loop; - - if (callback_) - { - callback_(&loop); - } - - { - MutexLockGuard lock(mutex_); - loop_ = &loop; - cond_.notify(); - } - - loop.loop(); - //assert(exiting_); - MutexLockGuard lock(mutex_); - loop_ = NULL; -} - diff --git a/include/muduo/net/EventLoopThread.h b/include/muduo/net/EventLoopThread.h deleted file mode 100644 index 7e839d7..0000000 --- a/include/muduo/net/EventLoopThread.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_EVENTLOOPTHREAD_H -#define MUDUO_NET_EVENTLOOPTHREAD_H - -#include "muduo/base/Condition.h" -#include "muduo/base/Mutex.h" -#include "muduo/base/Thread.h" - -namespace muduo -{ -namespace net -{ - -class EventLoop; - -class EventLoopThread : noncopyable -{ - public: - typedef std::function ThreadInitCallback; - - EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(), - const string& name = string()); - ~EventLoopThread(); - EventLoop* startLoop(); - - private: - void threadFunc(); - - EventLoop* loop_ GUARDED_BY(mutex_); - bool exiting_; - Thread thread_; - MutexLock mutex_; - Condition cond_ GUARDED_BY(mutex_); - ThreadInitCallback callback_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_EVENTLOOPTHREAD_H - diff --git a/include/muduo/net/EventLoopThreadPool.cc b/include/muduo/net/EventLoopThreadPool.cc deleted file mode 100644 index 1ee5949..0000000 --- a/include/muduo/net/EventLoopThreadPool.cc +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/EventLoopThreadPool.h" - -#include "muduo/net/EventLoop.h" -#include "muduo/net/EventLoopThread.h" - -#include - -using namespace muduo; -using namespace muduo::net; - -EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg) - : baseLoop_(baseLoop), - name_(nameArg), - started_(false), - numThreads_(0), - next_(0) -{ -} - -EventLoopThreadPool::~EventLoopThreadPool() -{ - // Don't delete loop, it's stack variable -} - -void EventLoopThreadPool::start(const ThreadInitCallback& cb) -{ - assert(!started_); - baseLoop_->assertInLoopThread(); - - started_ = true; - - for (int i = 0; i < numThreads_; ++i) - { - char buf[name_.size() + 32]; - snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i); - EventLoopThread* t = new EventLoopThread(cb, buf); - threads_.push_back(std::unique_ptr(t)); - loops_.push_back(t->startLoop()); - } - if (numThreads_ == 0 && cb) - { - cb(baseLoop_); - } -} - -EventLoop* EventLoopThreadPool::getNextLoop() -{ - baseLoop_->assertInLoopThread(); - assert(started_); - EventLoop* loop = baseLoop_; - - if (!loops_.empty()) - { - // round-robin - loop = loops_[next_]; - ++next_; - if (implicit_cast(next_) >= loops_.size()) - { - next_ = 0; - } - } - return loop; -} - -EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode) -{ - baseLoop_->assertInLoopThread(); - EventLoop* loop = baseLoop_; - - if (!loops_.empty()) - { - loop = loops_[hashCode % loops_.size()]; - } - return loop; -} - -std::vector EventLoopThreadPool::getAllLoops() -{ - baseLoop_->assertInLoopThread(); - assert(started_); - if (loops_.empty()) - { - return std::vector(1, baseLoop_); - } - else - { - return loops_; - } -} diff --git a/include/muduo/net/EventLoopThreadPool.h b/include/muduo/net/EventLoopThreadPool.h deleted file mode 100644 index 7389148..0000000 --- a/include/muduo/net/EventLoopThreadPool.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H -#define MUDUO_NET_EVENTLOOPTHREADPOOL_H - -#include "muduo/base/noncopyable.h" -#include "muduo/base/Types.h" - -#include -#include -#include - -namespace muduo -{ - -namespace net -{ - -class EventLoop; -class EventLoopThread; - -class EventLoopThreadPool : noncopyable -{ - public: - typedef std::function ThreadInitCallback; - - EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg); - ~EventLoopThreadPool(); - void setThreadNum(int numThreads) { numThreads_ = numThreads; } - void start(const ThreadInitCallback& cb = ThreadInitCallback()); - - // valid after calling start() - /// round-robin - EventLoop* getNextLoop(); - - /// with the same hash code, it will always return the same EventLoop - EventLoop* getLoopForHash(size_t hashCode); - - std::vector getAllLoops(); - - bool started() const - { return started_; } - - const string& name() const - { return name_; } - - private: - - EventLoop* baseLoop_; - string name_; - bool started_; - int numThreads_; - int next_; - std::vector> threads_; - std::vector loops_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H diff --git a/include/muduo/net/InetAddress.cc b/include/muduo/net/InetAddress.cc deleted file mode 100644 index 7c5e0ae..0000000 --- a/include/muduo/net/InetAddress.cc +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/InetAddress.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/Endian.h" -#include "muduo/net/SocketsOps.h" - -#include -#include - -// INADDR_ANY use (type)value casting. -#pragma GCC diagnostic ignored "-Wold-style-cast" -static const in_addr_t kInaddrAny = INADDR_ANY; -static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; -#pragma GCC diagnostic error "-Wold-style-cast" - -// /* Structure describing an Internet socket address. */ -// struct sockaddr_in { -// sa_family_t sin_family; /* address family: AF_INET */ -// uint16_t sin_port; /* port in network byte order */ -// struct in_addr sin_addr; /* internet address */ -// }; - -// /* Internet address. */ -// typedef uint32_t in_addr_t; -// struct in_addr { -// in_addr_t s_addr; /* address in network byte order */ -// }; - -// struct sockaddr_in6 { -// sa_family_t sin6_family; /* address family: AF_INET6 */ -// uint16_t sin6_port; /* port in network byte order */ -// uint32_t sin6_flowinfo; /* IPv6 flow information */ -// struct in6_addr sin6_addr; /* IPv6 address */ -// uint32_t sin6_scope_id; /* IPv6 scope-id */ -// }; - -using namespace muduo; -using namespace muduo::net; - -static_assert(sizeof(InetAddress) == sizeof(struct sockaddr_in6), - "InetAddress is same size as sockaddr_in6"); -static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0"); -static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0"); -static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2"); -static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2"); - -InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) -{ - static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0"); - static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0"); - if (ipv6) - { - memZero(&addr6_, sizeof addr6_); - addr6_.sin6_family = AF_INET6; - in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; - addr6_.sin6_addr = ip; - addr6_.sin6_port = sockets::hostToNetwork16(port); - } - else - { - memZero(&addr_, sizeof addr_); - addr_.sin_family = AF_INET; - in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; - addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip); - addr_.sin_port = sockets::hostToNetwork16(port); - } -} - -InetAddress::InetAddress(StringArg ip, uint16_t port, bool ipv6) -{ - if (ipv6 || strchr(ip.c_str(), ':')) - { - memZero(&addr6_, sizeof addr6_); - sockets::fromIpPort(ip.c_str(), port, &addr6_); - } - else - { - memZero(&addr_, sizeof addr_); - sockets::fromIpPort(ip.c_str(), port, &addr_); - } -} - -string InetAddress::toIpPort() const -{ - char buf[64] = ""; - sockets::toIpPort(buf, sizeof buf, getSockAddr()); - return buf; -} - -string InetAddress::toIp() const -{ - char buf[64] = ""; - sockets::toIp(buf, sizeof buf, getSockAddr()); - return buf; -} - -uint32_t InetAddress::ipv4NetEndian() const -{ - assert(family() == AF_INET); - return addr_.sin_addr.s_addr; -} - -uint16_t InetAddress::port() const -{ - return sockets::networkToHost16(portNetEndian()); -} - -static __thread char t_resolveBuffer[64 * 1024]; - -bool InetAddress::resolve(StringArg hostname, InetAddress* out) -{ - assert(out != NULL); - struct hostent hent; - struct hostent* he = NULL; - int herrno = 0; - memZero(&hent, sizeof(hent)); - - int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); - if (ret == 0 && he != NULL) - { - assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); - out->addr_.sin_addr = *reinterpret_cast(he->h_addr); - return true; - } - else - { - if (ret) - { - LOG_SYSERR << "InetAddress::resolve"; - } - return false; - } -} - -void InetAddress::setScopeId(uint32_t scope_id) -{ - if (family() == AF_INET6) - { - addr6_.sin6_scope_id = scope_id; - } -} diff --git a/include/muduo/net/InetAddress.h b/include/muduo/net/InetAddress.h deleted file mode 100644 index c5263a7..0000000 --- a/include/muduo/net/InetAddress.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_INETADDRESS_H -#define MUDUO_NET_INETADDRESS_H - -#include "muduo/base/copyable.h" -#include "muduo/base/StringPiece.h" - -#include - -namespace muduo -{ -namespace net -{ -namespace sockets -{ -const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); -} - -/// -/// Wrapper of sockaddr_in. -/// -/// This is an POD interface class. -class InetAddress : public muduo::copyable -{ - public: - /// Constructs an endpoint with given port number. - /// Mostly used in TcpServer listening. - explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); - - /// Constructs an endpoint with given ip and port. - /// @c ip should be "1.2.3.4" - InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); - - /// Constructs an endpoint with given struct @c sockaddr_in - /// Mostly used when accepting new connections - explicit InetAddress(const struct sockaddr_in& addr) - : addr_(addr) - { } - - explicit InetAddress(const struct sockaddr_in6& addr) - : addr6_(addr) - { } - - sa_family_t family() const { return addr_.sin_family; } - string toIp() const; - string toIpPort() const; - uint16_t port() const; - - // default copy/assignment are Okay - - const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); } - void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; } - - uint32_t ipv4NetEndian() const; - uint16_t portNetEndian() const { return addr_.sin_port; } - - // resolve hostname to IP address, not changing port or sin_family - // return true on success. - // thread safe - static bool resolve(StringArg hostname, InetAddress* result); - // static std::vector resolveAll(const char* hostname, uint16_t port = 0); - - // set IPv6 ScopeID - void setScopeId(uint32_t scope_id); - - private: - union - { - struct sockaddr_in addr_; - struct sockaddr_in6 addr6_; - }; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_INETADDRESS_H diff --git a/include/muduo/net/Poller.cc b/include/muduo/net/Poller.cc deleted file mode 100644 index cfe4c3c..0000000 --- a/include/muduo/net/Poller.cc +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/Poller.h" - -#include "muduo/net/Channel.h" - -using namespace muduo; -using namespace muduo::net; - -Poller::Poller(EventLoop* loop) - : ownerLoop_(loop) -{ -} - -Poller::~Poller() = default; - -bool Poller::hasChannel(Channel* channel) const -{ - assertInLoopThread(); - ChannelMap::const_iterator it = channels_.find(channel->fd()); - return it != channels_.end() && it->second == channel; -} - diff --git a/include/muduo/net/Poller.h b/include/muduo/net/Poller.h deleted file mode 100644 index 089e60b..0000000 --- a/include/muduo/net/Poller.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_POLLER_H -#define MUDUO_NET_POLLER_H - -#include -#include - -#include "muduo/base/Timestamp.h" -#include "muduo/net/EventLoop.h" - -namespace muduo -{ -namespace net -{ - -class Channel; - -/// -/// Base class for IO Multiplexing -/// -/// This class doesn't own the Channel objects. -class Poller : noncopyable -{ - public: - typedef std::vector ChannelList; - - Poller(EventLoop* loop); - virtual ~Poller(); - - /// Polls the I/O events. - /// Must be called in the loop thread. - virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; - - /// Changes the interested I/O events. - /// Must be called in the loop thread. - virtual void updateChannel(Channel* channel) = 0; - - /// Remove the channel, when it destructs. - /// Must be called in the loop thread. - virtual void removeChannel(Channel* channel) = 0; - - virtual bool hasChannel(Channel* channel) const; - - static Poller* newDefaultPoller(EventLoop* loop); - - void assertInLoopThread() const - { - ownerLoop_->assertInLoopThread(); - } - - protected: - typedef std::map ChannelMap; - ChannelMap channels_; - - private: - EventLoop* ownerLoop_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_POLLER_H diff --git a/include/muduo/net/Socket.cc b/include/muduo/net/Socket.cc deleted file mode 100644 index fc13147..0000000 --- a/include/muduo/net/Socket.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/Socket.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/InetAddress.h" -#include "muduo/net/SocketsOps.h" - -#include -#include -#include // snprintf - -using namespace muduo; -using namespace muduo::net; - -Socket::~Socket() -{ - sockets::close(sockfd_); -} - -bool Socket::getTcpInfo(struct tcp_info* tcpi) const -{ - socklen_t len = sizeof(*tcpi); - memZero(tcpi, len); - return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; -} - -bool Socket::getTcpInfoString(char* buf, int len) const -{ - struct tcp_info tcpi; - bool ok = getTcpInfo(&tcpi); - if (ok) - { - snprintf(buf, len, "unrecovered=%u " - "rto=%u ato=%u snd_mss=%u rcv_mss=%u " - "lost=%u retrans=%u rtt=%u rttvar=%u " - "sshthresh=%u cwnd=%u total_retrans=%u", - tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts - tcpi.tcpi_rto, // Retransmit timeout in usec - tcpi.tcpi_ato, // Predicted tick of soft clock in usec - tcpi.tcpi_snd_mss, - tcpi.tcpi_rcv_mss, - tcpi.tcpi_lost, // Lost packets - tcpi.tcpi_retrans, // Retransmitted packets out - tcpi.tcpi_rtt, // Smoothed round trip time in usec - tcpi.tcpi_rttvar, // Medium deviation - tcpi.tcpi_snd_ssthresh, - tcpi.tcpi_snd_cwnd, - tcpi.tcpi_total_retrans); // Total retransmits for entire connection - } - return ok; -} - -void Socket::bindAddress(const InetAddress& addr) -{ - sockets::bindOrDie(sockfd_, addr.getSockAddr()); -} - -void Socket::listen() -{ - sockets::listenOrDie(sockfd_); -} - -int Socket::accept(InetAddress* peeraddr) -{ - struct sockaddr_in6 addr; - memZero(&addr, sizeof addr); - int connfd = sockets::accept(sockfd_, &addr); - if (connfd >= 0) - { - peeraddr->setSockAddrInet6(addr); - } - return connfd; -} - -void Socket::shutdownWrite() -{ - sockets::shutdownWrite(sockfd_); -} - -void Socket::setTcpNoDelay(bool on) -{ - int optval = on ? 1 : 0; - ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, - &optval, static_cast(sizeof optval)); - // FIXME CHECK -} - -void Socket::setReuseAddr(bool on) -{ - int optval = on ? 1 : 0; - ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, - &optval, static_cast(sizeof optval)); - // FIXME CHECK -} - -void Socket::setReusePort(bool on) -{ -#ifdef SO_REUSEPORT - int optval = on ? 1 : 0; - int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, - &optval, static_cast(sizeof optval)); - if (ret < 0 && on) - { - LOG_SYSERR << "SO_REUSEPORT failed."; - } -#else - if (on) - { - LOG_ERROR << "SO_REUSEPORT is not supported."; - } -#endif -} - -void Socket::setKeepAlive(bool on) -{ - int optval = on ? 1 : 0; - ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, - &optval, static_cast(sizeof optval)); - // FIXME CHECK -} - diff --git a/include/muduo/net/Socket.h b/include/muduo/net/Socket.h deleted file mode 100644 index 17567be..0000000 --- a/include/muduo/net/Socket.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_SOCKET_H -#define MUDUO_NET_SOCKET_H - -#include "muduo/base/noncopyable.h" - -// struct tcp_info is in -struct tcp_info; - -namespace muduo -{ -/// -/// TCP networking. -/// -namespace net -{ - -class InetAddress; - -/// -/// Wrapper of socket file descriptor. -/// -/// It closes the sockfd when desctructs. -/// It's thread safe, all operations are delagated to OS. -class Socket : noncopyable -{ - public: - explicit Socket(int sockfd) - : sockfd_(sockfd) - { } - - // Socket(Socket&&) // move constructor in C++11 - ~Socket(); - - int fd() const { return sockfd_; } - // return true if success. - bool getTcpInfo(struct tcp_info*) const; - bool getTcpInfoString(char* buf, int len) const; - - /// abort if address in use - void bindAddress(const InetAddress& localaddr); - /// abort if address in use - void listen(); - - /// On success, returns a non-negative integer that is - /// a descriptor for the accepted socket, which has been - /// set to non-blocking and close-on-exec. *peeraddr is assigned. - /// On error, -1 is returned, and *peeraddr is untouched. - int accept(InetAddress* peeraddr); - - void shutdownWrite(); - - /// - /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). - /// - void setTcpNoDelay(bool on); - - /// - /// Enable/disable SO_REUSEADDR - /// - void setReuseAddr(bool on); - - /// - /// Enable/disable SO_REUSEPORT - /// - void setReusePort(bool on); - - /// - /// Enable/disable SO_KEEPALIVE - /// - void setKeepAlive(bool on); - - private: - const int sockfd_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_SOCKET_H diff --git a/include/muduo/net/SocketsOps.cc b/include/muduo/net/SocketsOps.cc deleted file mode 100644 index 465c507..0000000 --- a/include/muduo/net/SocketsOps.cc +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/SocketsOps.h" - -#include "muduo/base/Logging.h" -#include "muduo/base/Types.h" -#include "muduo/net/Endian.h" - -#include -#include -#include // snprintf -#include -#include // readv -#include - -using namespace muduo; -using namespace muduo::net; - -namespace -{ - -typedef struct sockaddr SA; - - -#if VALGRIND || defined (NO_ACCEPT4) -void setNonBlockAndCloseOnExec(int sockfd) -{ - // non-block - int flags = ::fcntl(sockfd, F_GETFL, 0); - flags |= O_NONBLOCK; - int ret = ::fcntl(sockfd, F_SETFL, flags); - // FIXME check - - // close-on-exec - flags = ::fcntl(sockfd, F_GETFD, 0); - flags |= FD_CLOEXEC; - ret = ::fcntl(sockfd, F_SETFD, flags); - // FIXME check - - (void)ret; -} -#endif - -} // namespace - -const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in6* addr) -{ - return static_cast(implicit_cast(addr)); -} - -struct sockaddr* sockets::sockaddr_cast(struct sockaddr_in6* addr) -{ - return static_cast(implicit_cast(addr)); -} - -const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in* addr) -{ - return static_cast(implicit_cast(addr)); -} - -const struct sockaddr_in* sockets::sockaddr_in_cast(const struct sockaddr* addr) -{ - return static_cast(implicit_cast(addr)); -} - -const struct sockaddr_in6* sockets::sockaddr_in6_cast(const struct sockaddr* addr) -{ - return static_cast(implicit_cast(addr)); -} - -int sockets::createNonblockingOrDie(sa_family_t family) -{ -#if VALGRIND - int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP); - if (sockfd < 0) - { - LOG_SYSFATAL << "sockets::createNonblockingOrDie"; - } - - setNonBlockAndCloseOnExec(sockfd); -#else - int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); - if (sockfd < 0) - { - LOG_SYSFATAL << "sockets::createNonblockingOrDie"; - } -#endif - return sockfd; -} - -void sockets::bindOrDie(int sockfd, const struct sockaddr* addr) -{ - int ret = ::bind(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); - if (ret < 0) - { - LOG_SYSFATAL << "sockets::bindOrDie"; - } -} - -void sockets::listenOrDie(int sockfd) -{ - int ret = ::listen(sockfd, SOMAXCONN); - if (ret < 0) - { - LOG_SYSFATAL << "sockets::listenOrDie"; - } -} - -int sockets::accept(int sockfd, struct sockaddr_in6* addr) -{ - socklen_t addrlen = static_cast(sizeof *addr); -#if VALGRIND || defined (NO_ACCEPT4) - int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); - setNonBlockAndCloseOnExec(connfd); -#else - int connfd = ::accept4(sockfd, sockaddr_cast(addr), - &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); -#endif - if (connfd < 0) - { - int savedErrno = errno; - LOG_SYSERR << "Socket::accept"; - switch (savedErrno) - { - case EAGAIN: - case ECONNABORTED: - case EINTR: - case EPROTO: // ??? - case EPERM: - case EMFILE: // per-process lmit of open file desctiptor ??? - // expected errors - errno = savedErrno; - break; - case EBADF: - case EFAULT: - case EINVAL: - case ENFILE: - case ENOBUFS: - case ENOMEM: - case ENOTSOCK: - case EOPNOTSUPP: - // unexpected errors - LOG_FATAL << "unexpected error of ::accept " << savedErrno; - break; - default: - LOG_FATAL << "unknown error of ::accept " << savedErrno; - break; - } - } - return connfd; -} - -int sockets::connect(int sockfd, const struct sockaddr* addr) -{ - return ::connect(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); -} - -ssize_t sockets::read(int sockfd, void *buf, size_t count) -{ - return ::read(sockfd, buf, count); -} - -ssize_t sockets::readv(int sockfd, const struct iovec *iov, int iovcnt) -{ - return ::readv(sockfd, iov, iovcnt); -} - -ssize_t sockets::write(int sockfd, const void *buf, size_t count) -{ - return ::write(sockfd, buf, count); -} - -void sockets::close(int sockfd) -{ - if (::close(sockfd) < 0) - { - LOG_SYSERR << "sockets::close"; - } -} - -void sockets::shutdownWrite(int sockfd) -{ - if (::shutdown(sockfd, SHUT_WR) < 0) - { - LOG_SYSERR << "sockets::shutdownWrite"; - } -} - -void sockets::toIpPort(char* buf, size_t size, - const struct sockaddr* addr) -{ - if (addr->sa_family == AF_INET6) - { - buf[0] = '['; - toIp(buf+1, size-1, addr); - size_t end = ::strlen(buf); - const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); - uint16_t port = sockets::networkToHost16(addr6->sin6_port); - assert(size > end); - snprintf(buf+end, size-end, "]:%u", port); - return; - } - toIp(buf, size, addr); - size_t end = ::strlen(buf); - const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); - uint16_t port = sockets::networkToHost16(addr4->sin_port); - assert(size > end); - snprintf(buf+end, size-end, ":%u", port); -} - -void sockets::toIp(char* buf, size_t size, - const struct sockaddr* addr) -{ - if (addr->sa_family == AF_INET) - { - assert(size >= INET_ADDRSTRLEN); - const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); - ::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast(size)); - } - else if (addr->sa_family == AF_INET6) - { - assert(size >= INET6_ADDRSTRLEN); - const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); - ::inet_ntop(AF_INET6, &addr6->sin6_addr, buf, static_cast(size)); - } -} - -void sockets::fromIpPort(const char* ip, uint16_t port, - struct sockaddr_in* addr) -{ - addr->sin_family = AF_INET; - addr->sin_port = hostToNetwork16(port); - if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) - { - LOG_SYSERR << "sockets::fromIpPort"; - } -} - -void sockets::fromIpPort(const char* ip, uint16_t port, - struct sockaddr_in6* addr) -{ - addr->sin6_family = AF_INET6; - addr->sin6_port = hostToNetwork16(port); - if (::inet_pton(AF_INET6, ip, &addr->sin6_addr) <= 0) - { - LOG_SYSERR << "sockets::fromIpPort"; - } -} - -int sockets::getSocketError(int sockfd) -{ - int optval; - socklen_t optlen = static_cast(sizeof optval); - - if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) - { - return errno; - } - else - { - return optval; - } -} - -struct sockaddr_in6 sockets::getLocalAddr(int sockfd) -{ - struct sockaddr_in6 localaddr; - memZero(&localaddr, sizeof localaddr); - socklen_t addrlen = static_cast(sizeof localaddr); - if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) - { - LOG_SYSERR << "sockets::getLocalAddr"; - } - return localaddr; -} - -struct sockaddr_in6 sockets::getPeerAddr(int sockfd) -{ - struct sockaddr_in6 peeraddr; - memZero(&peeraddr, sizeof peeraddr); - socklen_t addrlen = static_cast(sizeof peeraddr); - if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) - { - LOG_SYSERR << "sockets::getPeerAddr"; - } - return peeraddr; -} - -bool sockets::isSelfConnect(int sockfd) -{ - struct sockaddr_in6 localaddr = getLocalAddr(sockfd); - struct sockaddr_in6 peeraddr = getPeerAddr(sockfd); - if (localaddr.sin6_family == AF_INET) - { - const struct sockaddr_in* laddr4 = reinterpret_cast(&localaddr); - const struct sockaddr_in* raddr4 = reinterpret_cast(&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) - { - return localaddr.sin6_port == peeraddr.sin6_port - && memcmp(&localaddr.sin6_addr, &peeraddr.sin6_addr, sizeof localaddr.sin6_addr) == 0; - } - else - { - return false; - } -} - diff --git a/include/muduo/net/SocketsOps.h b/include/muduo/net/SocketsOps.h deleted file mode 100644 index 9c46597..0000000 --- a/include/muduo/net/SocketsOps.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_SOCKETSOPS_H -#define MUDUO_NET_SOCKETSOPS_H - -#include - -namespace muduo -{ -namespace net -{ -namespace sockets -{ - -/// -/// Creates a non-blocking socket file descriptor, -/// abort if any error. -int createNonblockingOrDie(sa_family_t family); - -int connect(int sockfd, const struct sockaddr* addr); -void bindOrDie(int sockfd, const struct sockaddr* addr); -void listenOrDie(int sockfd); -int accept(int sockfd, struct sockaddr_in6* addr); -ssize_t read(int sockfd, void *buf, size_t count); -ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); -ssize_t write(int sockfd, const void *buf, size_t count); -void close(int sockfd); -void shutdownWrite(int sockfd); - -void toIpPort(char* buf, size_t size, - const struct sockaddr* addr); -void toIp(char* buf, size_t size, - const struct sockaddr* addr); - -void fromIpPort(const char* ip, uint16_t port, - struct sockaddr_in* addr); -void fromIpPort(const char* ip, uint16_t port, - struct sockaddr_in6* addr); - -int getSocketError(int sockfd); - -const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); -const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); -struct sockaddr* sockaddr_cast(struct sockaddr_in6* addr); -const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); -const struct sockaddr_in6* sockaddr_in6_cast(const struct sockaddr* addr); - -struct sockaddr_in6 getLocalAddr(int sockfd); -struct sockaddr_in6 getPeerAddr(int sockfd); -bool isSelfConnect(int sockfd); - -} // namespace sockets -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_SOCKETSOPS_H diff --git a/include/muduo/net/TcpClient.cc b/include/muduo/net/TcpClient.cc deleted file mode 100644 index 1e668b3..0000000 --- a/include/muduo/net/TcpClient.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/TcpClient.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/Connector.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/SocketsOps.h" - -#include // snprintf - -using namespace muduo; -using namespace muduo::net; - -// TcpClient::TcpClient(EventLoop* loop) -// : loop_(loop) -// { -// } - -// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) -// : loop_(CHECK_NOTNULL(loop)), -// serverAddr_(host, port) -// { -// } - -namespace muduo -{ -namespace net -{ -namespace detail -{ - -void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn) -{ - loop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); -} - -void removeConnector(const ConnectorPtr& connector) -{ - //connector-> -} - -} // namespace detail -} // namespace net -} // namespace muduo - -TcpClient::TcpClient(EventLoop* loop, - const InetAddress& serverAddr, - const string& nameArg) - : loop_(CHECK_NOTNULL(loop)), - connector_(new Connector(loop, serverAddr)), - name_(nameArg), - connectionCallback_(defaultConnectionCallback), - messageCallback_(defaultMessageCallback), - retry_(false), - connect_(true), - nextConnId_(1) -{ - connector_->setNewConnectionCallback( - std::bind(&TcpClient::newConnection, this, _1)); - // FIXME setConnectFailedCallback - LOG_INFO << "TcpClient::TcpClient[" << name_ - << "] - connector " << get_pointer(connector_); -} - -TcpClient::~TcpClient() -{ - LOG_INFO << "TcpClient::~TcpClient[" << name_ - << "] - connector " << get_pointer(connector_); - TcpConnectionPtr conn; - bool unique = false; - { - MutexLockGuard lock(mutex_); - unique = connection_.unique(); - conn = connection_; - } - if (conn) - { - assert(loop_ == conn->getLoop()); - // FIXME: not 100% safe, if we are in different thread - CloseCallback cb = std::bind(&detail::removeConnection, loop_, _1); - loop_->runInLoop( - std::bind(&TcpConnection::setCloseCallback, conn, cb)); - if (unique) - { - conn->forceClose(); - } - } - else - { - connector_->stop(); - // FIXME: HACK - loop_->runAfter(1, std::bind(&detail::removeConnector, connector_)); - } -} - -void TcpClient::connect() -{ - // FIXME: check state - LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to " - << connector_->serverAddress().toIpPort(); - connect_ = true; - connector_->start(); -} - -void TcpClient::disconnect() -{ - connect_ = false; - - { - MutexLockGuard lock(mutex_); - if (connection_) - { - connection_->shutdown(); - } - } -} - -void TcpClient::stop() -{ - connect_ = false; - connector_->stop(); -} - -void TcpClient::newConnection(int sockfd) -{ - loop_->assertInLoopThread(); - InetAddress peerAddr(sockets::getPeerAddr(sockfd)); - char buf[32]; - snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toIpPort().c_str(), nextConnId_); - ++nextConnId_; - string connName = name_ + buf; - - InetAddress localAddr(sockets::getLocalAddr(sockfd)); - // FIXME poll with zero timeout to double confirm the new connection - // FIXME use make_shared if necessary - TcpConnectionPtr conn(new TcpConnection(loop_, - connName, - sockfd, - localAddr, - peerAddr)); - - conn->setConnectionCallback(connectionCallback_); - conn->setMessageCallback(messageCallback_); - conn->setWriteCompleteCallback(writeCompleteCallback_); - conn->setCloseCallback( - std::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe - { - MutexLockGuard lock(mutex_); - connection_ = conn; - } - conn->connectEstablished(); -} - -void TcpClient::removeConnection(const TcpConnectionPtr& conn) -{ - loop_->assertInLoopThread(); - assert(loop_ == conn->getLoop()); - - { - MutexLockGuard lock(mutex_); - assert(connection_ == conn); - connection_.reset(); - } - - loop_->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); - if (retry_ && connect_) - { - LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to " - << connector_->serverAddress().toIpPort(); - connector_->restart(); - } -} - diff --git a/include/muduo/net/TcpClient.h b/include/muduo/net/TcpClient.h deleted file mode 100644 index c498cb3..0000000 --- a/include/muduo/net/TcpClient.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_TCPCLIENT_H -#define MUDUO_NET_TCPCLIENT_H - -#include "muduo/base/Mutex.h" -#include "muduo/net/TcpConnection.h" - -namespace muduo -{ -namespace net -{ - -class Connector; -typedef std::shared_ptr ConnectorPtr; - -class TcpClient : noncopyable -{ - public: - // TcpClient(EventLoop* loop); - // TcpClient(EventLoop* loop, const string& host, uint16_t port); - TcpClient(EventLoop* loop, - const InetAddress& serverAddr, - const string& nameArg); - ~TcpClient(); // force out-line dtor, for std::unique_ptr members. - - void connect(); - void disconnect(); - void stop(); - - TcpConnectionPtr connection() const - { - MutexLockGuard lock(mutex_); - return connection_; - } - - EventLoop* getLoop() const { return loop_; } - bool retry() const { return retry_; } - void enableRetry() { retry_ = true; } - - const string& name() const - { return name_; } - - /// Set connection callback. - /// Not thread safe. - void setConnectionCallback(ConnectionCallback cb) - { connectionCallback_ = std::move(cb); } - - /// Set message callback. - /// Not thread safe. - void setMessageCallback(MessageCallback cb) - { messageCallback_ = std::move(cb); } - - /// Set write complete callback. - /// Not thread safe. - void setWriteCompleteCallback(WriteCompleteCallback cb) - { writeCompleteCallback_ = std::move(cb); } - - private: - /// Not thread safe, but in loop - void newConnection(int sockfd); - /// Not thread safe, but in loop - void removeConnection(const TcpConnectionPtr& conn); - - EventLoop* loop_; - ConnectorPtr connector_; // avoid revealing Connector - const string name_; - ConnectionCallback connectionCallback_; - MessageCallback messageCallback_; - WriteCompleteCallback writeCompleteCallback_; - bool retry_; // atomic - bool connect_; // atomic - // always in loop thread - int nextConnId_; - mutable MutexLock mutex_; - TcpConnectionPtr connection_ GUARDED_BY(mutex_); -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_TCPCLIENT_H diff --git a/include/muduo/net/TcpConnection.cc b/include/muduo/net/TcpConnection.cc deleted file mode 100644 index 37f58a4..0000000 --- a/include/muduo/net/TcpConnection.cc +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/TcpConnection.h" - -#include "muduo/base/Logging.h" -#include "muduo/base/WeakCallback.h" -#include "muduo/net/Channel.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/Socket.h" -#include "muduo/net/SocketsOps.h" - -#include - -using namespace muduo; -using namespace muduo::net; - -void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn) -{ - LOG_TRACE << conn->localAddress().toIpPort() << " -> " - << conn->peerAddress().toIpPort() << " is " - << (conn->connected() ? "UP" : "DOWN"); - // do not call conn->forceClose(), because some users want to register message callback only. -} - -void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, - Buffer* buf, - Timestamp) -{ - buf->retrieveAll(); -} - -TcpConnection::TcpConnection(EventLoop* loop, - const string& nameArg, - int sockfd, - const InetAddress& localAddr, - const InetAddress& peerAddr) - : loop_(CHECK_NOTNULL(loop)), - name_(nameArg), - state_(kConnecting), - reading_(true), - socket_(new Socket(sockfd)), - channel_(new Channel(loop, sockfd)), - localAddr_(localAddr), - peerAddr_(peerAddr), - highWaterMark_(64*1024*1024) -{ - channel_->setReadCallback( - std::bind(&TcpConnection::handleRead, this, _1)); - channel_->setWriteCallback( - std::bind(&TcpConnection::handleWrite, this)); - channel_->setCloseCallback( - std::bind(&TcpConnection::handleClose, this)); - channel_->setErrorCallback( - std::bind(&TcpConnection::handleError, this)); - LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this - << " fd=" << sockfd; - socket_->setKeepAlive(true); -} - -TcpConnection::~TcpConnection() -{ - LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this - << " fd=" << channel_->fd() - << " state=" << stateToString(); - assert(state_ == kDisconnected); -} - -bool TcpConnection::getTcpInfo(struct tcp_info* tcpi) const -{ - return socket_->getTcpInfo(tcpi); -} - -string TcpConnection::getTcpInfoString() const -{ - char buf[1024]; - buf[0] = '\0'; - socket_->getTcpInfoString(buf, sizeof buf); - return buf; -} - -void TcpConnection::send(const void* data, int len) -{ - send(StringPiece(static_cast(data), len)); -} - -void TcpConnection::send(const StringPiece& message) -{ - if (state_ == kConnected) - { - if (loop_->isInLoopThread()) - { - sendInLoop(message); - } - else - { - void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; - loop_->runInLoop( - std::bind(fp, - this, // FIXME - message.as_string())); - //std::forward(message))); - } - } -} - -// FIXME efficiency!!! -void TcpConnection::send(Buffer* buf) -{ - if (state_ == kConnected) - { - if (loop_->isInLoopThread()) - { - sendInLoop(buf->peek(), buf->readableBytes()); - buf->retrieveAll(); - } - else - { - void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; - loop_->runInLoop( - std::bind(fp, - this, // FIXME - buf->retrieveAllAsString())); - //std::forward(message))); - } - } -} - -void TcpConnection::sendInLoop(const StringPiece& message) -{ - sendInLoop(message.data(), message.size()); -} - -void TcpConnection::sendInLoop(const void* data, size_t len) -{ - loop_->assertInLoopThread(); - ssize_t nwrote = 0; - size_t remaining = len; - bool faultError = false; - if (state_ == kDisconnected) - { - LOG_WARN << "disconnected, give up writing"; - return; - } - // if no thing in output queue, try writing directly - if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) - { - nwrote = sockets::write(channel_->fd(), data, len); - if (nwrote >= 0) - { - remaining = len - nwrote; - if (remaining == 0 && writeCompleteCallback_) - { - loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); - } - } - else // nwrote < 0 - { - nwrote = 0; - if (errno != EWOULDBLOCK) - { - LOG_SYSERR << "TcpConnection::sendInLoop"; - if (errno == EPIPE || errno == ECONNRESET) // FIXME: any others? - { - faultError = true; - } - } - } - } - - assert(remaining <= len); - if (!faultError && remaining > 0) - { - size_t oldLen = outputBuffer_.readableBytes(); - if (oldLen + remaining >= highWaterMark_ - && oldLen < highWaterMark_ - && highWaterMarkCallback_) - { - loop_->queueInLoop(std::bind(highWaterMarkCallback_, shared_from_this(), oldLen + remaining)); - } - outputBuffer_.append(static_cast(data)+nwrote, remaining); - if (!channel_->isWriting()) - { - channel_->enableWriting(); - } - } -} - -void TcpConnection::shutdown() -{ - // FIXME: use compare and swap - if (state_ == kConnected) - { - setState(kDisconnecting); - // FIXME: shared_from_this()? - loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this)); - } -} - -void TcpConnection::shutdownInLoop() -{ - loop_->assertInLoopThread(); - if (!channel_->isWriting()) - { - // we are not writing - socket_->shutdownWrite(); - } -} - -// void TcpConnection::shutdownAndForceCloseAfter(double seconds) -// { -// // FIXME: use compare and swap -// if (state_ == kConnected) -// { -// setState(kDisconnecting); -// loop_->runInLoop(std::bind(&TcpConnection::shutdownAndForceCloseInLoop, this, seconds)); -// } -// } - -// void TcpConnection::shutdownAndForceCloseInLoop(double seconds) -// { -// loop_->assertInLoopThread(); -// if (!channel_->isWriting()) -// { -// // we are not writing -// socket_->shutdownWrite(); -// } -// loop_->runAfter( -// seconds, -// makeWeakCallback(shared_from_this(), -// &TcpConnection::forceCloseInLoop)); -// } - -void TcpConnection::forceClose() -{ - // FIXME: use compare and swap - if (state_ == kConnected || state_ == kDisconnecting) - { - setState(kDisconnecting); - loop_->queueInLoop(std::bind(&TcpConnection::forceCloseInLoop, shared_from_this())); - } -} - -void TcpConnection::forceCloseWithDelay(double seconds) -{ - if (state_ == kConnected || state_ == kDisconnecting) - { - setState(kDisconnecting); - loop_->runAfter( - seconds, - makeWeakCallback(shared_from_this(), - &TcpConnection::forceClose)); // not forceCloseInLoop to avoid race condition - } -} - -void TcpConnection::forceCloseInLoop() -{ - loop_->assertInLoopThread(); - if (state_ == kConnected || state_ == kDisconnecting) - { - // as if we received 0 byte in handleRead(); - handleClose(); - } -} - -const char* TcpConnection::stateToString() const -{ - switch (state_) - { - case kDisconnected: - return "kDisconnected"; - case kConnecting: - return "kConnecting"; - case kConnected: - return "kConnected"; - case kDisconnecting: - return "kDisconnecting"; - default: - return "unknown state"; - } -} - -void TcpConnection::setTcpNoDelay(bool on) -{ - socket_->setTcpNoDelay(on); -} - -void TcpConnection::startRead() -{ - loop_->runInLoop(std::bind(&TcpConnection::startReadInLoop, this)); -} - -void TcpConnection::startReadInLoop() -{ - loop_->assertInLoopThread(); - if (!reading_ || !channel_->isReading()) - { - channel_->enableReading(); - reading_ = true; - } -} - -void TcpConnection::stopRead() -{ - loop_->runInLoop(std::bind(&TcpConnection::stopReadInLoop, this)); -} - -void TcpConnection::stopReadInLoop() -{ - loop_->assertInLoopThread(); - if (reading_ || channel_->isReading()) - { - channel_->disableReading(); - reading_ = false; - } -} - -void TcpConnection::connectEstablished() -{ - loop_->assertInLoopThread(); - assert(state_ == kConnecting); - setState(kConnected); - channel_->tie(shared_from_this()); - channel_->enableReading(); - - connectionCallback_(shared_from_this()); -} - -void TcpConnection::connectDestroyed() -{ - loop_->assertInLoopThread(); - if (state_ == kConnected) - { - setState(kDisconnected); - channel_->disableAll(); - - connectionCallback_(shared_from_this()); - } - channel_->remove(); -} - -void TcpConnection::handleRead(Timestamp receiveTime) -{ - loop_->assertInLoopThread(); - int savedErrno = 0; - ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno); - if (n > 0) - { - messageCallback_(shared_from_this(), &inputBuffer_, receiveTime); - } - else if (n == 0) - { - handleClose(); - } - else - { - errno = savedErrno; - LOG_SYSERR << "TcpConnection::handleRead"; - handleError(); - } -} - -void TcpConnection::handleWrite() -{ - loop_->assertInLoopThread(); - if (channel_->isWriting()) - { - ssize_t n = sockets::write(channel_->fd(), - outputBuffer_.peek(), - outputBuffer_.readableBytes()); - if (n > 0) - { - outputBuffer_.retrieve(n); - if (outputBuffer_.readableBytes() == 0) - { - channel_->disableWriting(); - if (writeCompleteCallback_) - { - loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); - } - if (state_ == kDisconnecting) - { - shutdownInLoop(); - } - } - } - else - { - LOG_SYSERR << "TcpConnection::handleWrite"; - // if (state_ == kDisconnecting) - // { - // shutdownInLoop(); - // } - } - } - else - { - LOG_TRACE << "Connection fd = " << channel_->fd() - << " is down, no more writing"; - } -} - -void TcpConnection::handleClose() -{ - loop_->assertInLoopThread(); - LOG_TRACE << "fd = " << channel_->fd() << " state = " << stateToString(); - assert(state_ == kConnected || state_ == kDisconnecting); - // we don't close fd, leave it to dtor, so we can find leaks easily. - setState(kDisconnected); - channel_->disableAll(); - - TcpConnectionPtr guardThis(shared_from_this()); - connectionCallback_(guardThis); - // must be the last line - closeCallback_(guardThis); -} - -void TcpConnection::handleError() -{ - int err = sockets::getSocketError(channel_->fd()); - LOG_ERROR << "TcpConnection::handleError [" << name_ - << "] - SO_ERROR = " << err << " " << strerror_tl(err); -} - diff --git a/include/muduo/net/TcpConnection.h b/include/muduo/net/TcpConnection.h deleted file mode 100644 index cb76331..0000000 --- a/include/muduo/net/TcpConnection.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_TCPCONNECTION_H -#define MUDUO_NET_TCPCONNECTION_H - -#include "muduo/base/noncopyable.h" -#include "muduo/base/StringPiece.h" -#include "muduo/base/Types.h" -#include "muduo/net/Callbacks.h" -#include "muduo/net/Buffer.h" -#include "muduo/net/InetAddress.h" - -#include - -#include - -// struct tcp_info is in -struct tcp_info; - -namespace muduo -{ -namespace net -{ - -class Channel; -class EventLoop; -class Socket; - -/// -/// TCP connection, for both client and server usage. -/// -/// This is an interface class, so don't expose too much details. -class TcpConnection : noncopyable, - public std::enable_shared_from_this -{ - public: - /// Constructs a TcpConnection with a connected sockfd - /// - /// User should not create this object. - TcpConnection(EventLoop* loop, - const string& name, - int sockfd, - const InetAddress& localAddr, - const InetAddress& peerAddr); - ~TcpConnection(); - - EventLoop* getLoop() const { return loop_; } - const string& name() const { return name_; } - const InetAddress& localAddress() const { return localAddr_; } - const InetAddress& peerAddress() const { return peerAddr_; } - bool connected() const { return state_ == kConnected; } - bool disconnected() const { return state_ == kDisconnected; } - // return true if success. - bool getTcpInfo(struct tcp_info*) const; - string getTcpInfoString() const; - - // void send(string&& message); // C++11 - void send(const void* message, int len); - void send(const StringPiece& message); - // void send(Buffer&& message); // C++11 - void send(Buffer* message); // this one will swap data - void shutdown(); // NOT thread safe, no simultaneous calling - // void shutdownAndForceCloseAfter(double seconds); // NOT thread safe, no simultaneous calling - void forceClose(); - void forceCloseWithDelay(double seconds); - void setTcpNoDelay(bool on); - // reading or not - void startRead(); - void stopRead(); - bool isReading() const { return reading_; }; // NOT thread safe, may race with start/stopReadInLoop - - void setContext(const boost::any& context) - { context_ = context; } - - const boost::any& getContext() const - { return context_; } - - boost::any* getMutableContext() - { return &context_; } - - void setConnectionCallback(const ConnectionCallback& cb) - { connectionCallback_ = cb; } - - void setMessageCallback(const MessageCallback& cb) - { messageCallback_ = cb; } - - void setWriteCompleteCallback(const WriteCompleteCallback& cb) - { writeCompleteCallback_ = cb; } - - void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark) - { highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark; } - - /// Advanced interface - Buffer* inputBuffer() - { return &inputBuffer_; } - - Buffer* outputBuffer() - { return &outputBuffer_; } - - /// Internal use only. - void setCloseCallback(const CloseCallback& cb) - { closeCallback_ = cb; } - - // called when TcpServer accepts a new connection - void connectEstablished(); // should be called only once - // called when TcpServer has removed me from its map - void connectDestroyed(); // should be called only once - - private: - enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting }; - void handleRead(Timestamp receiveTime); - void handleWrite(); - void handleClose(); - void handleError(); - // void sendInLoop(string&& message); - void sendInLoop(const StringPiece& message); - void sendInLoop(const void* message, size_t len); - void shutdownInLoop(); - // void shutdownAndForceCloseInLoop(double seconds); - void forceCloseInLoop(); - void setState(StateE s) { state_ = s; } - const char* stateToString() const; - void startReadInLoop(); - void stopReadInLoop(); - - EventLoop* loop_; - const string name_; - StateE state_; // FIXME: use atomic variable - bool reading_; - // we don't expose those classes to client. - std::unique_ptr socket_; - std::unique_ptr channel_; - const InetAddress localAddr_; - const InetAddress peerAddr_; - ConnectionCallback connectionCallback_; - MessageCallback messageCallback_; - WriteCompleteCallback writeCompleteCallback_; - HighWaterMarkCallback highWaterMarkCallback_; - CloseCallback closeCallback_; - size_t highWaterMark_; - Buffer inputBuffer_; - Buffer outputBuffer_; // FIXME: use list as output buffer. - boost::any context_; - // FIXME: creationTime_, lastReceiveTime_ - // bytesReceived_, bytesSent_ -}; - -typedef std::shared_ptr TcpConnectionPtr; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_TCPCONNECTION_H diff --git a/include/muduo/net/TcpServer.cc b/include/muduo/net/TcpServer.cc deleted file mode 100644 index e4f8e24..0000000 --- a/include/muduo/net/TcpServer.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/TcpServer.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/Acceptor.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/EventLoopThreadPool.h" -#include "muduo/net/SocketsOps.h" - -#include // snprintf - -using namespace muduo; -using namespace muduo::net; - -TcpServer::TcpServer(EventLoop* loop, - const InetAddress& listenAddr, - const string& nameArg, - Option option) - : loop_(CHECK_NOTNULL(loop)), - ipPort_(listenAddr.toIpPort()), - name_(nameArg), - acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), - threadPool_(new EventLoopThreadPool(loop, name_)), - connectionCallback_(defaultConnectionCallback), - messageCallback_(defaultMessageCallback), - nextConnId_(1) -{ - acceptor_->setNewConnectionCallback( - std::bind(&TcpServer::newConnection, this, _1, _2)); -} - -TcpServer::~TcpServer() -{ - loop_->assertInLoopThread(); - LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; - - for (auto& item : connections_) - { - TcpConnectionPtr conn(item.second); - item.second.reset(); - conn->getLoop()->runInLoop( - std::bind(&TcpConnection::connectDestroyed, conn)); - } -} - -void TcpServer::setThreadNum(int numThreads) -{ - assert(0 <= numThreads); - threadPool_->setThreadNum(numThreads); -} - -void TcpServer::start() -{ - if (started_.getAndSet(1) == 0) - { - threadPool_->start(threadInitCallback_); - - assert(!acceptor_->listening()); - loop_->runInLoop( - std::bind(&Acceptor::listen, get_pointer(acceptor_))); - } -} - -void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) -{ - loop_->assertInLoopThread(); - EventLoop* ioLoop = threadPool_->getNextLoop(); - char buf[64]; - snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_); - ++nextConnId_; - string connName = name_ + buf; - - LOG_INFO << "TcpServer::newConnection [" << name_ - << "] - new connection [" << connName - << "] from " << peerAddr.toIpPort(); - InetAddress localAddr(sockets::getLocalAddr(sockfd)); - // FIXME poll with zero timeout to double confirm the new connection - // FIXME use make_shared if necessary - TcpConnectionPtr conn(new TcpConnection(ioLoop, - connName, - sockfd, - localAddr, - peerAddr)); - connections_[connName] = conn; - conn->setConnectionCallback(connectionCallback_); - conn->setMessageCallback(messageCallback_); - conn->setWriteCompleteCallback(writeCompleteCallback_); - conn->setCloseCallback( - std::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe - ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn)); -} - -void TcpServer::removeConnection(const TcpConnectionPtr& conn) -{ - // FIXME: unsafe - loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn)); -} - -void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) -{ - loop_->assertInLoopThread(); - LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ - << "] - connection " << conn->name(); - size_t n = connections_.erase(conn->name()); - (void)n; - assert(n == 1); - EventLoop* ioLoop = conn->getLoop(); - ioLoop->queueInLoop( - std::bind(&TcpConnection::connectDestroyed, conn)); -} - diff --git a/include/muduo/net/TcpServer.h b/include/muduo/net/TcpServer.h deleted file mode 100644 index 3fbfead..0000000 --- a/include/muduo/net/TcpServer.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_TCPSERVER_H -#define MUDUO_NET_TCPSERVER_H - -#include "muduo/base/Atomic.h" -#include "muduo/base/Types.h" -#include "muduo/net/TcpConnection.h" - -#include - -namespace muduo -{ -namespace net -{ - -class Acceptor; -class EventLoop; -class EventLoopThreadPool; - -/// -/// TCP server, supports single-threaded and thread-pool models. -/// -/// This is an interface class, so don't expose too much details. -class TcpServer : noncopyable -{ - public: - typedef std::function ThreadInitCallback; - enum Option - { - kNoReusePort, - kReusePort, - }; - - //TcpServer(EventLoop* loop, const InetAddress& listenAddr); - TcpServer(EventLoop* loop, - const InetAddress& listenAddr, - const string& nameArg, - Option option = kNoReusePort); - ~TcpServer(); // force out-line dtor, for std::unique_ptr members. - - const string& ipPort() const { return ipPort_; } - const string& name() const { return name_; } - EventLoop* getLoop() const { return loop_; } - - /// Set the number of threads for handling input. - /// - /// Always accepts new connection in loop's thread. - /// Must be called before @c start - /// @param numThreads - /// - 0 means all I/O in loop's thread, no thread will created. - /// this is the default value. - /// - 1 means all I/O in another thread. - /// - N means a thread pool with N threads, new connections - /// are assigned on a round-robin basis. - void setThreadNum(int numThreads); - void setThreadInitCallback(const ThreadInitCallback& cb) - { threadInitCallback_ = cb; } - /// valid after calling start() - std::shared_ptr threadPool() - { return threadPool_; } - - /// Starts the server if it's not listening. - /// - /// It's harmless to call it multiple times. - /// Thread safe. - void start(); - - /// Set connection callback. - /// Not thread safe. - void setConnectionCallback(const ConnectionCallback& cb) - { connectionCallback_ = cb; } - - /// Set message callback. - /// Not thread safe. - void setMessageCallback(const MessageCallback& cb) - { messageCallback_ = cb; } - - /// Set write complete callback. - /// Not thread safe. - void setWriteCompleteCallback(const WriteCompleteCallback& cb) - { writeCompleteCallback_ = cb; } - - private: - /// Not thread safe, but in loop - void newConnection(int sockfd, const InetAddress& peerAddr); - /// Thread safe. - void removeConnection(const TcpConnectionPtr& conn); - /// Not thread safe, but in loop - void removeConnectionInLoop(const TcpConnectionPtr& conn); - - typedef std::map ConnectionMap; - - EventLoop* loop_; // the acceptor loop - const string ipPort_; - const string name_; - std::unique_ptr acceptor_; // avoid revealing Acceptor - std::shared_ptr threadPool_; - ConnectionCallback connectionCallback_; - MessageCallback messageCallback_; - WriteCompleteCallback writeCompleteCallback_; - ThreadInitCallback threadInitCallback_; - AtomicInt32 started_; - // always in loop thread - int nextConnId_; - ConnectionMap connections_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_TCPSERVER_H diff --git a/include/muduo/net/Timer.cc b/include/muduo/net/Timer.cc deleted file mode 100644 index a4d4433..0000000 --- a/include/muduo/net/Timer.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/Timer.h" - -using namespace muduo; -using namespace muduo::net; - -AtomicInt64 Timer::s_numCreated_; - -void Timer::restart(Timestamp now) -{ - if (repeat_) - { - expiration_ = addTime(now, interval_); - } - else - { - expiration_ = Timestamp::invalid(); - } -} diff --git a/include/muduo/net/Timer.h b/include/muduo/net/Timer.h deleted file mode 100644 index 904584e..0000000 --- a/include/muduo/net/Timer.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_TIMER_H -#define MUDUO_NET_TIMER_H - -#include "muduo/base/Atomic.h" -#include "muduo/base/Timestamp.h" -#include "muduo/net/Callbacks.h" - -namespace muduo -{ -namespace net -{ - -/// -/// Internal class for timer event. -/// -class Timer : noncopyable -{ - public: - Timer(TimerCallback cb, Timestamp when, double interval) - : callback_(std::move(cb)), - expiration_(when), - interval_(interval), - repeat_(interval > 0.0), - sequence_(s_numCreated_.incrementAndGet()) - { } - - void run() const - { - callback_(); - } - - Timestamp expiration() const { return expiration_; } - bool repeat() const { return repeat_; } - int64_t sequence() const { return sequence_; } - - void restart(Timestamp now); - - static int64_t numCreated() { return s_numCreated_.get(); } - - private: - const TimerCallback callback_; - Timestamp expiration_; - const double interval_; - const bool repeat_; - const int64_t sequence_; - - static AtomicInt64 s_numCreated_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_TIMER_H diff --git a/include/muduo/net/TimerId.h b/include/muduo/net/TimerId.h deleted file mode 100644 index fcc5264..0000000 --- a/include/muduo/net/TimerId.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_TIMERID_H -#define MUDUO_NET_TIMERID_H - -#include "muduo/base/copyable.h" - -namespace muduo -{ -namespace net -{ - -class Timer; - -/// -/// An opaque identifier, for canceling Timer. -/// -class TimerId : public muduo::copyable -{ - public: - TimerId() - : timer_(NULL), - sequence_(0) - { - } - - TimerId(Timer* timer, int64_t seq) - : timer_(timer), - sequence_(seq) - { - } - - // default copy-ctor, dtor and assignment are okay - - friend class TimerQueue; - - private: - Timer* timer_; - int64_t sequence_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_TIMERID_H diff --git a/include/muduo/net/TimerQueue.cc b/include/muduo/net/TimerQueue.cc deleted file mode 100644 index 89119ae..0000000 --- a/include/muduo/net/TimerQueue.cc +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS -#endif - -#include "muduo/net/TimerQueue.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/Timer.h" -#include "muduo/net/TimerId.h" - -#include -#include - -namespace muduo -{ -namespace net -{ -namespace detail -{ - -int createTimerfd() -{ - int timerfd = ::timerfd_create(CLOCK_MONOTONIC, - TFD_NONBLOCK | TFD_CLOEXEC); - if (timerfd < 0) - { - LOG_SYSFATAL << "Failed in timerfd_create"; - } - return timerfd; -} - -struct timespec howMuchTimeFromNow(Timestamp when) -{ - int64_t microseconds = when.microSecondsSinceEpoch() - - Timestamp::now().microSecondsSinceEpoch(); - if (microseconds < 100) - { - microseconds = 100; - } - struct timespec ts; - ts.tv_sec = static_cast( - microseconds / Timestamp::kMicroSecondsPerSecond); - ts.tv_nsec = static_cast( - (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); - return ts; -} - -void readTimerfd(int timerfd, Timestamp now) -{ - uint64_t howmany; - ssize_t n = ::read(timerfd, &howmany, sizeof howmany); - LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); - if (n != sizeof howmany) - { - LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; - } -} - -void resetTimerfd(int timerfd, Timestamp expiration) -{ - // wake up loop by timerfd_settime() - struct itimerspec newValue; - struct itimerspec oldValue; - memZero(&newValue, sizeof newValue); - memZero(&oldValue, sizeof oldValue); - newValue.it_value = howMuchTimeFromNow(expiration); - int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); - if (ret) - { - LOG_SYSERR << "timerfd_settime()"; - } -} - -} // namespace detail -} // namespace net -} // namespace muduo - -using namespace muduo; -using namespace muduo::net; -using namespace muduo::net::detail; - -TimerQueue::TimerQueue(EventLoop* loop) - : loop_(loop), - timerfd_(createTimerfd()), - timerfdChannel_(loop, timerfd_), - timers_(), - callingExpiredTimers_(false) -{ - timerfdChannel_.setReadCallback( - std::bind(&TimerQueue::handleRead, this)); - // we are always reading the timerfd, we disarm it with timerfd_settime. - timerfdChannel_.enableReading(); -} - -TimerQueue::~TimerQueue() -{ - timerfdChannel_.disableAll(); - timerfdChannel_.remove(); - ::close(timerfd_); - // do not remove channel, since we're in EventLoop::dtor(); - for (const Entry& timer : timers_) - { - delete timer.second; - } -} - -TimerId TimerQueue::addTimer(TimerCallback cb, - Timestamp when, - double interval) -{ - Timer* timer = new Timer(std::move(cb), when, interval); - loop_->runInLoop( - std::bind(&TimerQueue::addTimerInLoop, this, timer)); - return TimerId(timer, timer->sequence()); -} - -void TimerQueue::cancel(TimerId timerId) -{ - loop_->runInLoop( - std::bind(&TimerQueue::cancelInLoop, this, timerId)); -} - -void TimerQueue::addTimerInLoop(Timer* timer) -{ - loop_->assertInLoopThread(); - bool earliestChanged = insert(timer); - - if (earliestChanged) - { - resetTimerfd(timerfd_, timer->expiration()); - } -} - -void TimerQueue::cancelInLoop(TimerId timerId) -{ - loop_->assertInLoopThread(); - assert(timers_.size() == activeTimers_.size()); - ActiveTimer timer(timerId.timer_, timerId.sequence_); - ActiveTimerSet::iterator it = activeTimers_.find(timer); - if (it != activeTimers_.end()) - { - size_t n = timers_.erase(Entry(it->first->expiration(), it->first)); - assert(n == 1); (void)n; - delete it->first; // FIXME: no delete please - activeTimers_.erase(it); - } - else if (callingExpiredTimers_) - { - cancelingTimers_.insert(timer); - } - assert(timers_.size() == activeTimers_.size()); -} - -void TimerQueue::handleRead() -{ - loop_->assertInLoopThread(); - Timestamp now(Timestamp::now()); - readTimerfd(timerfd_, now); - - std::vector expired = getExpired(now); - - callingExpiredTimers_ = true; - cancelingTimers_.clear(); - // safe to callback outside critical section - for (const Entry& it : expired) - { - it.second->run(); - } - callingExpiredTimers_ = false; - - reset(expired, now); -} - -std::vector TimerQueue::getExpired(Timestamp now) -{ - assert(timers_.size() == activeTimers_.size()); - std::vector expired; - Entry sentry(now, reinterpret_cast(UINTPTR_MAX)); - TimerList::iterator end = timers_.lower_bound(sentry); - assert(end == timers_.end() || now < end->first); - std::copy(timers_.begin(), end, back_inserter(expired)); - timers_.erase(timers_.begin(), end); - - for (const Entry& it : expired) - { - ActiveTimer timer(it.second, it.second->sequence()); - size_t n = activeTimers_.erase(timer); - assert(n == 1); (void)n; - } - - assert(timers_.size() == activeTimers_.size()); - return expired; -} - -void TimerQueue::reset(const std::vector& expired, Timestamp now) -{ - Timestamp nextExpire; - - for (const Entry& it : expired) - { - ActiveTimer timer(it.second, it.second->sequence()); - if (it.second->repeat() - && cancelingTimers_.find(timer) == cancelingTimers_.end()) - { - it.second->restart(now); - insert(it.second); - } - else - { - // FIXME move to a free list - delete it.second; // FIXME: no delete please - } - } - - if (!timers_.empty()) - { - nextExpire = timers_.begin()->second->expiration(); - } - - if (nextExpire.valid()) - { - resetTimerfd(timerfd_, nextExpire); - } -} - -bool TimerQueue::insert(Timer* timer) -{ - loop_->assertInLoopThread(); - assert(timers_.size() == activeTimers_.size()); - bool earliestChanged = false; - Timestamp when = timer->expiration(); - TimerList::iterator it = timers_.begin(); - if (it == timers_.end() || when < it->first) - { - earliestChanged = true; - } - { - std::pair result - = timers_.insert(Entry(when, timer)); - assert(result.second); (void)result; - } - { - std::pair result - = activeTimers_.insert(ActiveTimer(timer, timer->sequence())); - assert(result.second); (void)result; - } - - assert(timers_.size() == activeTimers_.size()); - return earliestChanged; -} - diff --git a/include/muduo/net/TimerQueue.h b/include/muduo/net/TimerQueue.h deleted file mode 100644 index 85da6b7..0000000 --- a/include/muduo/net/TimerQueue.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_TIMERQUEUE_H -#define MUDUO_NET_TIMERQUEUE_H - -#include -#include - -#include "muduo/base/Mutex.h" -#include "muduo/base/Timestamp.h" -#include "muduo/net/Callbacks.h" -#include "muduo/net/Channel.h" - -namespace muduo -{ -namespace net -{ - -class EventLoop; -class Timer; -class TimerId; - -/// -/// A best efforts timer queue. -/// No guarantee that the callback will be on time. -/// -class TimerQueue : noncopyable -{ - public: - explicit TimerQueue(EventLoop* loop); - ~TimerQueue(); - - /// - /// Schedules the callback to be run at given time, - /// repeats if @c interval > 0.0. - /// - /// Must be thread safe. Usually be called from other threads. - TimerId addTimer(TimerCallback cb, - Timestamp when, - double interval); - - void cancel(TimerId timerId); - - private: - - // FIXME: use unique_ptr instead of raw pointers. - // This requires heterogeneous comparison lookup (N3465) from C++14 - // so that we can find an T* in a set>. - typedef std::pair Entry; - typedef std::set TimerList; - typedef std::pair ActiveTimer; - typedef std::set ActiveTimerSet; - - void addTimerInLoop(Timer* timer); - void cancelInLoop(TimerId timerId); - // called when timerfd alarms - void handleRead(); - // move out all expired timers - std::vector getExpired(Timestamp now); - void reset(const std::vector& expired, Timestamp now); - - bool insert(Timer* timer); - - EventLoop* loop_; - const int timerfd_; - Channel timerfdChannel_; - // Timer list sorted by expiration - TimerList timers_; - - // for cancel() - ActiveTimerSet activeTimers_; - bool callingExpiredTimers_; /* atomic */ - ActiveTimerSet cancelingTimers_; -}; - -} // namespace net -} // namespace muduo -#endif // MUDUO_NET_TIMERQUEUE_H diff --git a/include/muduo/net/ZlibStream.h b/include/muduo/net/ZlibStream.h deleted file mode 100644 index 0f143b0..0000000 --- a/include/muduo/net/ZlibStream.h +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include "muduo/base/noncopyable.h" -#include "muduo/net/Buffer.h" -#pragma GCC diagnostic ignored "-Wold-style-cast" -#include - -namespace muduo -{ -namespace net -{ - -// input is zlib compressed data, output uncompressed data -// FIXME: finish this -class ZlibInputStream : noncopyable -{ - public: - explicit ZlibInputStream(Buffer* output) - : output_(output), - zerror_(Z_OK) - { - memZero(&zstream_, sizeof zstream_); - zerror_ = inflateInit(&zstream_); - } - - ~ZlibInputStream() - { - finish(); - } - - bool write(StringPiece buf); - bool write(Buffer* input); - bool finish(); - // inflateEnd(&zstream_); - - private: - int decompress(int flush); - - Buffer* output_; - z_stream zstream_; - int zerror_; -}; - -// input is uncompressed data, output zlib compressed data -class ZlibOutputStream : noncopyable -{ - public: - explicit ZlibOutputStream(Buffer* output) - : output_(output), - zerror_(Z_OK), - bufferSize_(1024) - { - memZero(&zstream_, sizeof zstream_); - zerror_ = deflateInit(&zstream_, Z_DEFAULT_COMPRESSION); - } - - ~ZlibOutputStream() - { - finish(); - } - - // Return last error message or NULL if no error. - const char* zlibErrorMessage() const { return zstream_.msg; } - - int zlibErrorCode() const { return zerror_; } - int64_t inputBytes() const { return zstream_.total_in; } - int64_t outputBytes() const { return zstream_.total_out; } - int internalOutputBufferSize() const { return bufferSize_; } - - bool write(StringPiece buf) - { - if (zerror_ != Z_OK) - return false; - - assert(zstream_.next_in == NULL && zstream_.avail_in == 0); - void* in = const_cast(buf.data()); - zstream_.next_in = static_cast(in); - zstream_.avail_in = buf.size(); - while (zstream_.avail_in > 0 && zerror_ == Z_OK) - { - zerror_ = compress(Z_NO_FLUSH); - } - if (zstream_.avail_in == 0) - { - assert(static_cast(zstream_.next_in) == buf.end()); - zstream_.next_in = NULL; - } - return zerror_ == Z_OK; - } - - // compress input as much as possible, not guarantee consuming all data. - bool write(Buffer* input) - { - if (zerror_ != Z_OK) - return false; - - void* in = const_cast(input->peek()); - zstream_.next_in = static_cast(in); - zstream_.avail_in = static_cast(input->readableBytes()); - if (zstream_.avail_in > 0 && zerror_ == Z_OK) - { - zerror_ = compress(Z_NO_FLUSH); - } - input->retrieve(input->readableBytes() - zstream_.avail_in); - return zerror_ == Z_OK; - } - - bool finish() - { - if (zerror_ != Z_OK) - return false; - - while (zerror_ == Z_OK) - { - zerror_ = compress(Z_FINISH); - } - zerror_ = deflateEnd(&zstream_); - bool ok = zerror_ == Z_OK; - zerror_ = Z_STREAM_END; - return ok; - } - - private: - int compress(int flush) - { - output_->ensureWritableBytes(bufferSize_); - zstream_.next_out = reinterpret_cast(output_->beginWrite()); - zstream_.avail_out = static_cast(output_->writableBytes()); - int error = ::deflate(&zstream_, flush); - output_->hasWritten(output_->writableBytes() - zstream_.avail_out); - if (output_->writableBytes() == 0 && bufferSize_ < 65536) - { - bufferSize_ *= 2; - } - return error; - } - - Buffer* output_; - z_stream zstream_; - int zerror_; - int bufferSize_; -}; - -} // namespace net -} // namespace muduo diff --git a/include/muduo/net/boilerplate.cc b/include/muduo/net/boilerplate.cc deleted file mode 100644 index d0ebe26..0000000 --- a/include/muduo/net/boilerplate.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/BoilerPlate.h" - -using namespace muduo; -using namespace muduo::net; - - diff --git a/include/muduo/net/boilerplate.h b/include/muduo/net/boilerplate.h deleted file mode 100644 index 780661c..0000000 --- a/include/muduo/net/boilerplate.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_BOILERPLATE_H -#define MUDUO_NET_BOILERPLATE_H - -#include "muduo/base/noncopyable.h" - -namespace muduo -{ -namespace net -{ - -class BoilerPlate : noncopyable -{ - public: - - private: -}; - -} -} - -#endif // MUDUO_NET_BOILERPLATE_H diff --git a/include/muduo/net/http/BUILD.bazel b/include/muduo/net/http/BUILD.bazel deleted file mode 100644 index 08b98a4..0000000 --- a/include/muduo/net/http/BUILD.bazel +++ /dev/null @@ -1,9 +0,0 @@ -cc_library( - name = "http", - srcs = glob(["*.cc"]), - hdrs = glob(["*.h"]), - visibility = ["//visibility:public"], - deps = [ - "//muduo/net", - ], -) diff --git a/include/muduo/net/http/CMakeLists.txt b/include/muduo/net/http/CMakeLists.txt deleted file mode 100644 index 51dd981..0000000 --- a/include/muduo/net/http/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -set(http_SRCS - HttpServer.cc - HttpResponse.cc - HttpContext.cc - ) - -add_library(muduo_http ${http_SRCS}) -target_link_libraries(muduo_http muduo_net) - -install(TARGETS muduo_http DESTINATION lib) -set(HEADERS - HttpContext.h - HttpRequest.h - HttpResponse.h - HttpServer.h - ) -install(FILES ${HEADERS} DESTINATION include/muduo/net/http) - -if(MUDUO_BUILD_EXAMPLES) -add_executable(httpserver_test tests/HttpServer_test.cc) -target_link_libraries(httpserver_test muduo_http) - -if(BOOSTTEST_LIBRARY) -add_executable(httprequest_unittest tests/HttpRequest_unittest.cc) -target_link_libraries(httprequest_unittest muduo_http boost_unit_test_framework) -endif() - -endif() - -# add_subdirectory(tests) diff --git a/include/muduo/net/http/HttpContext.cc b/include/muduo/net/http/HttpContext.cc deleted file mode 100644 index bef3a80..0000000 --- a/include/muduo/net/http/HttpContext.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/Buffer.h" -#include "muduo/net/http/HttpContext.h" - -using namespace muduo; -using namespace muduo::net; - -bool HttpContext::processRequestLine(const char* begin, const char* end) -{ - bool succeed = false; - const char* start = begin; - const char* space = std::find(start, end, ' '); - if (space != end && request_.setMethod(start, space)) - { - start = space+1; - space = std::find(start, end, ' '); - if (space != end) - { - const char* question = std::find(start, space, '?'); - if (question != space) - { - request_.setPath(start, question); - request_.setQuery(question, space); - } - else - { - request_.setPath(start, space); - } - start = space+1; - succeed = end-start == 8 && std::equal(start, end-1, "HTTP/1."); - if (succeed) - { - if (*(end-1) == '1') - { - request_.setVersion(HttpRequest::kHttp11); - } - else if (*(end-1) == '0') - { - request_.setVersion(HttpRequest::kHttp10); - } - else - { - succeed = false; - } - } - } - } - return succeed; -} - -// return false if any error -bool HttpContext::parseRequest(Buffer* buf, Timestamp receiveTime) -{ - bool ok = true; - bool hasMore = true; - while (hasMore) - { - if (state_ == kExpectRequestLine) - { - const char* crlf = buf->findCRLF(); - if (crlf) - { - ok = processRequestLine(buf->peek(), crlf); - if (ok) - { - request_.setReceiveTime(receiveTime); - buf->retrieveUntil(crlf + 2); - state_ = kExpectHeaders; - } - else - { - hasMore = false; - } - } - else - { - hasMore = false; - } - } - else if (state_ == kExpectHeaders) - { - const char* crlf = buf->findCRLF(); - if (crlf) - { - const char* colon = std::find(buf->peek(), crlf, ':'); - if (colon != crlf) - { - request_.addHeader(buf->peek(), colon, crlf); - } - else - { - // empty line, end of header - // FIXME: - state_ = kGotAll; - hasMore = false; - } - buf->retrieveUntil(crlf + 2); - } - else - { - hasMore = false; - } - } - else if (state_ == kExpectBody) - { - // FIXME: - } - } - return ok; -} diff --git a/include/muduo/net/http/HttpContext.h b/include/muduo/net/http/HttpContext.h deleted file mode 100644 index 4beee5c..0000000 --- a/include/muduo/net/http/HttpContext.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H -#define MUDUO_NET_HTTP_HTTPCONTEXT_H - -#include "muduo/base/copyable.h" - -#include "muduo/net/http/HttpRequest.h" - -namespace muduo -{ -namespace net -{ - -class Buffer; - -class HttpContext : public muduo::copyable -{ - public: - enum HttpRequestParseState - { - kExpectRequestLine, - kExpectHeaders, - kExpectBody, - kGotAll, - }; - - HttpContext() - : state_(kExpectRequestLine) - { - } - - // default copy-ctor, dtor and assignment are fine - - // return false if any error - bool parseRequest(Buffer* buf, Timestamp receiveTime); - - bool gotAll() const - { return state_ == kGotAll; } - - void reset() - { - state_ = kExpectRequestLine; - HttpRequest dummy; - request_.swap(dummy); - } - - const HttpRequest& request() const - { return request_; } - - HttpRequest& request() - { return request_; } - - private: - bool processRequestLine(const char* begin, const char* end); - - HttpRequestParseState state_; - HttpRequest request_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_HTTP_HTTPCONTEXT_H diff --git a/include/muduo/net/http/HttpRequest.h b/include/muduo/net/http/HttpRequest.h deleted file mode 100644 index 9c70c5d..0000000 --- a/include/muduo/net/http/HttpRequest.h +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H -#define MUDUO_NET_HTTP_HTTPREQUEST_H - -#include "muduo/base/copyable.h" -#include "muduo/base/Timestamp.h" -#include "muduo/base/Types.h" - -#include -#include -#include - -namespace muduo -{ -namespace net -{ - -class HttpRequest : public muduo::copyable -{ - public: - enum Method - { - kInvalid, kGet, kPost, kHead, kPut, kDelete - }; - enum Version - { - kUnknown, kHttp10, kHttp11 - }; - - HttpRequest() - : method_(kInvalid), - version_(kUnknown) - { - } - - void setVersion(Version v) - { - version_ = v; - } - - Version getVersion() const - { return version_; } - - bool setMethod(const char* start, const char* end) - { - assert(method_ == kInvalid); - string m(start, end); - if (m == "GET") - { - method_ = kGet; - } - else if (m == "POST") - { - method_ = kPost; - } - else if (m == "HEAD") - { - method_ = kHead; - } - else if (m == "PUT") - { - method_ = kPut; - } - else if (m == "DELETE") - { - method_ = kDelete; - } - else - { - method_ = kInvalid; - } - return method_ != kInvalid; - } - - Method method() const - { return method_; } - - const char* methodString() const - { - const char* result = "UNKNOWN"; - switch(method_) - { - case kGet: - result = "GET"; - break; - case kPost: - result = "POST"; - break; - case kHead: - result = "HEAD"; - break; - case kPut: - result = "PUT"; - break; - case kDelete: - result = "DELETE"; - break; - default: - break; - } - return result; - } - - void setPath(const char* start, const char* end) - { - path_.assign(start, end); - } - - const string& path() const - { return path_; } - - void setQuery(const char* start, const char* end) - { - query_.assign(start, end); - } - - const string& query() const - { return query_; } - - void setReceiveTime(Timestamp t) - { receiveTime_ = t; } - - Timestamp receiveTime() const - { return receiveTime_; } - - void addHeader(const char* start, const char* colon, const char* end) - { - string field(start, colon); - ++colon; - while (colon < end && isspace(*colon)) - { - ++colon; - } - string value(colon, end); - while (!value.empty() && isspace(value[value.size()-1])) - { - value.resize(value.size()-1); - } - headers_[field] = value; - } - - string getHeader(const string& field) const - { - string result; - std::map::const_iterator it = headers_.find(field); - if (it != headers_.end()) - { - result = it->second; - } - return result; - } - - const std::map& headers() const - { return headers_; } - - void swap(HttpRequest& that) - { - std::swap(method_, that.method_); - std::swap(version_, that.version_); - path_.swap(that.path_); - query_.swap(that.query_); - receiveTime_.swap(that.receiveTime_); - headers_.swap(that.headers_); - } - - private: - Method method_; - Version version_; - string path_; - string query_; - Timestamp receiveTime_; - std::map headers_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_HTTP_HTTPREQUEST_H diff --git a/include/muduo/net/http/HttpResponse.cc b/include/muduo/net/http/HttpResponse.cc deleted file mode 100644 index 0e2e74d..0000000 --- a/include/muduo/net/http/HttpResponse.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/http/HttpResponse.h" -#include "muduo/net/Buffer.h" - -#include - -using namespace muduo; -using namespace muduo::net; - -void HttpResponse::appendToBuffer(Buffer* output) const -{ - char buf[32]; - snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); - output->append(buf); - output->append(statusMessage_); - output->append("\r\n"); - - if (closeConnection_) - { - output->append("Connection: close\r\n"); - } - else - { - snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size()); - output->append(buf); - output->append("Connection: Keep-Alive\r\n"); - } - - for (const auto& header : headers_) - { - output->append(header.first); - output->append(": "); - output->append(header.second); - output->append("\r\n"); - } - - output->append("\r\n"); - output->append(body_); -} diff --git a/include/muduo/net/http/HttpResponse.h b/include/muduo/net/http/HttpResponse.h deleted file mode 100644 index eb3910f..0000000 --- a/include/muduo/net/http/HttpResponse.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H -#define MUDUO_NET_HTTP_HTTPRESPONSE_H - -#include "muduo/base/copyable.h" -#include "muduo/base/Types.h" - -#include - -namespace muduo -{ -namespace net -{ - -class Buffer; -class HttpResponse : public muduo::copyable -{ - public: - enum HttpStatusCode - { - kUnknown, - k200Ok = 200, - k301MovedPermanently = 301, - k400BadRequest = 400, - k404NotFound = 404, - }; - - explicit HttpResponse(bool close) - : statusCode_(kUnknown), - closeConnection_(close) - { - } - - void setStatusCode(HttpStatusCode code) - { statusCode_ = code; } - - void setStatusMessage(const string& message) - { statusMessage_ = message; } - - void setCloseConnection(bool on) - { closeConnection_ = on; } - - bool closeConnection() const - { return closeConnection_; } - - void setContentType(const string& contentType) - { addHeader("Content-Type", contentType); } - - // FIXME: replace string with StringPiece - void addHeader(const string& key, const string& value) - { headers_[key] = value; } - - void setBody(const string& body) - { body_ = body; } - - void appendToBuffer(Buffer* output) const; - - private: - std::map headers_; - HttpStatusCode statusCode_; - // FIXME: add http version - string statusMessage_; - bool closeConnection_; - string body_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_HTTP_HTTPRESPONSE_H diff --git a/include/muduo/net/http/HttpServer.cc b/include/muduo/net/http/HttpServer.cc deleted file mode 100644 index f7d4678..0000000 --- a/include/muduo/net/http/HttpServer.cc +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/http/HttpServer.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/http/HttpContext.h" -#include "muduo/net/http/HttpRequest.h" -#include "muduo/net/http/HttpResponse.h" - -using namespace muduo; -using namespace muduo::net; - -namespace muduo -{ -namespace net -{ -namespace detail -{ - -void defaultHttpCallback(const HttpRequest&, HttpResponse* resp) -{ - resp->setStatusCode(HttpResponse::k404NotFound); - resp->setStatusMessage("Not Found"); - resp->setCloseConnection(true); -} - -} // namespace detail -} // namespace net -} // namespace muduo - -HttpServer::HttpServer(EventLoop* loop, - const InetAddress& listenAddr, - const string& name, - TcpServer::Option option) - : server_(loop, listenAddr, name, option), - httpCallback_(detail::defaultHttpCallback) -{ - server_.setConnectionCallback( - std::bind(&HttpServer::onConnection, this, _1)); - server_.setMessageCallback( - std::bind(&HttpServer::onMessage, this, _1, _2, _3)); -} - -void HttpServer::start() -{ - LOG_WARN << "HttpServer[" << server_.name() - << "] starts listening on " << server_.ipPort(); - server_.start(); -} - -void HttpServer::onConnection(const TcpConnectionPtr& conn) -{ - if (conn->connected()) - { - conn->setContext(HttpContext()); - } -} - -void HttpServer::onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime) -{ - HttpContext* context = boost::any_cast(conn->getMutableContext()); - - if (!context->parseRequest(buf, receiveTime)) - { - conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); - conn->shutdown(); - } - - if (context->gotAll()) - { - onRequest(conn, context->request()); - context->reset(); - } -} - -void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) -{ - const string& connection = req.getHeader("Connection"); - bool close = connection == "close" || - (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive"); - HttpResponse response(close); - httpCallback_(req, &response); - Buffer buf; - response.appendToBuffer(&buf); - conn->send(&buf); - if (response.closeConnection()) - { - conn->shutdown(); - } -} - diff --git a/include/muduo/net/http/HttpServer.h b/include/muduo/net/http/HttpServer.h deleted file mode 100644 index 9609a11..0000000 --- a/include/muduo/net/http/HttpServer.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_HTTP_HTTPSERVER_H -#define MUDUO_NET_HTTP_HTTPSERVER_H - -#include "muduo/net/TcpServer.h" - -namespace muduo -{ -namespace net -{ - -class HttpRequest; -class HttpResponse; - -/// A simple embeddable HTTP server designed for report status of a program. -/// It is not a fully HTTP 1.1 compliant server, but provides minimum features -/// that can communicate with HttpClient and Web browser. -/// It is synchronous, just like Java Servlet. -class HttpServer : noncopyable -{ - public: - typedef std::function HttpCallback; - - HttpServer(EventLoop* loop, - const InetAddress& listenAddr, - const string& name, - TcpServer::Option option = TcpServer::kNoReusePort); - - EventLoop* getLoop() const { return server_.getLoop(); } - - /// Not thread safe, callback be registered before calling start(). - void setHttpCallback(const HttpCallback& cb) - { - httpCallback_ = cb; - } - - void setThreadNum(int numThreads) - { - server_.setThreadNum(numThreads); - } - - void start(); - - private: - void onConnection(const TcpConnectionPtr& conn); - void onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime); - void onRequest(const TcpConnectionPtr&, const HttpRequest&); - - TcpServer server_; - HttpCallback httpCallback_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_HTTP_HTTPSERVER_H diff --git a/include/muduo/net/http/tests/HttpRequest_unittest.cc b/include/muduo/net/http/tests/HttpRequest_unittest.cc deleted file mode 100644 index cb89305..0000000 --- a/include/muduo/net/http/tests/HttpRequest_unittest.cc +++ /dev/null @@ -1,79 +0,0 @@ -#include "muduo/net/http/HttpContext.h" -#include "muduo/net/Buffer.h" - -//#define BOOST_TEST_MODULE BufferTest -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include - -using muduo::string; -using muduo::Timestamp; -using muduo::net::Buffer; -using muduo::net::HttpContext; -using muduo::net::HttpRequest; - -BOOST_AUTO_TEST_CASE(testParseRequestAllInOne) -{ - HttpContext context; - Buffer input; - input.append("GET /index.html HTTP/1.1\r\n" - "Host: www.chenshuo.com\r\n" - "\r\n"); - - BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); - BOOST_CHECK(context.gotAll()); - const HttpRequest& request = context.request(); - BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); - BOOST_CHECK_EQUAL(request.path(), string("/index.html")); - BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); - BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); - BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); -} - -BOOST_AUTO_TEST_CASE(testParseRequestInTwoPieces) -{ - string all("GET /index.html HTTP/1.1\r\n" - "Host: www.chenshuo.com\r\n" - "\r\n"); - - for (size_t sz1 = 0; sz1 < all.size(); ++sz1) - { - HttpContext context; - Buffer input; - input.append(all.c_str(), sz1); - BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); - BOOST_CHECK(!context.gotAll()); - - size_t sz2 = all.size() - sz1; - input.append(all.c_str() + sz1, sz2); - BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); - BOOST_CHECK(context.gotAll()); - const HttpRequest& request = context.request(); - BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); - BOOST_CHECK_EQUAL(request.path(), string("/index.html")); - BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); - BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); - BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); - } -} - -BOOST_AUTO_TEST_CASE(testParseRequestEmptyHeaderValue) -{ - HttpContext context; - Buffer input; - input.append("GET /index.html HTTP/1.1\r\n" - "Host: www.chenshuo.com\r\n" - "User-Agent:\r\n" - "Accept-Encoding: \r\n" - "\r\n"); - - BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); - BOOST_CHECK(context.gotAll()); - const HttpRequest& request = context.request(); - BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); - BOOST_CHECK_EQUAL(request.path(), string("/index.html")); - BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); - BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); - BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); - BOOST_CHECK_EQUAL(request.getHeader("Accept-Encoding"), string("")); -} diff --git a/include/muduo/net/http/tests/HttpServer_test.cc b/include/muduo/net/http/tests/HttpServer_test.cc deleted file mode 100644 index 0ec38fb..0000000 --- a/include/muduo/net/http/tests/HttpServer_test.cc +++ /dev/null @@ -1,150 +0,0 @@ -#include "muduo/net/http/HttpServer.h" -#include "muduo/net/http/HttpRequest.h" -#include "muduo/net/http/HttpResponse.h" -#include "muduo/net/EventLoop.h" -#include "muduo/base/Logging.h" - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -extern char favicon[555]; -bool benchmark = false; - -void onRequest(const HttpRequest& req, HttpResponse* resp) -{ - std::cout << "Headers " << req.methodString() << " " << req.path() << std::endl; - if (!benchmark) - { - const std::map& headers = req.headers(); - for (const auto& header : headers) - { - std::cout << header.first << ": " << header.second << std::endl; - } - } - - if (req.path() == "/") - { - resp->setStatusCode(HttpResponse::k200Ok); - resp->setStatusMessage("OK"); - resp->setContentType("text/html"); - resp->addHeader("Server", "Muduo"); - string now = Timestamp::now().toFormattedString(); - resp->setBody("This is title" - "

Hello

Now is " + now + - ""); - } - else if (req.path() == "/favicon.ico") - { - resp->setStatusCode(HttpResponse::k200Ok); - resp->setStatusMessage("OK"); - resp->setContentType("image/png"); - resp->setBody(string(favicon, sizeof favicon)); - } - else if (req.path() == "/hello") - { - resp->setStatusCode(HttpResponse::k200Ok); - resp->setStatusMessage("OK"); - resp->setContentType("text/plain"); - resp->addHeader("Server", "Muduo"); - resp->setBody("hello, world!\n"); - } - else - { - resp->setStatusCode(HttpResponse::k404NotFound); - resp->setStatusMessage("Not Found"); - resp->setCloseConnection(true); - } -} - -int main(int argc, char* argv[]) -{ - int numThreads = 0; - if (argc > 1) - { - benchmark = true; - Logger::setLogLevel(Logger::WARN); - numThreads = atoi(argv[1]); - } - EventLoop loop; - HttpServer server(&loop, InetAddress(8000), "dummy"); - server.setHttpCallback(onRequest); - server.setThreadNum(numThreads); - server.start(); - loop.loop(); -} - -char favicon[555] = { - '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA', - '\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R', - '\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10', - '\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF', - 'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X', - 't', 'S', 'o', 'f', 't', 'w', 'a', 'r', - 'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20', - 'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a', - 'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0', - '\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA', - '\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86', - '\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm', - '\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16', - 'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8', - 'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0', - 'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4', - 'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1', - 'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB', - 'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F', - 'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v', - 'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8', - '\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5', - '\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC', - '\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA', - '\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F', - '\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r', - '9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6', - '\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T', - '\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3', - 'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R', - '\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x', - '\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0', - '\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9', - 'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11', - '\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5', - '3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4', - '\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98', - '\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3', - '\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C', - '\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB', - '\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9', - 'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6', - '\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C', - '\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f', - 'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9', - 'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F', - '\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22', - '\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15', - '\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j', - '\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F', - 'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40', - '\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A', - '\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE', - '\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD', - '\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0', - '\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB', - '\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2', - '\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4', - '\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A', - '\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91', - '\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7', - 'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N', - 'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E', - '\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u', - '\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB', - '\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF', - '\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K', - '\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0', - '\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE', - 'B', '\x60', '\x82', -}; diff --git a/include/muduo/net/inspect/BUILD.bazel b/include/muduo/net/inspect/BUILD.bazel deleted file mode 100644 index 0592e50..0000000 --- a/include/muduo/net/inspect/BUILD.bazel +++ /dev/null @@ -1,9 +0,0 @@ -cc_library( - name = "inspect", - srcs = glob(["*.cc"]), - hdrs = glob(["*.h"]), - visibility = ["//visibility:public"], - deps = [ - "//muduo/net/http", - ], -) diff --git a/include/muduo/net/inspect/CMakeLists.txt b/include/muduo/net/inspect/CMakeLists.txt deleted file mode 100644 index 1ce908f..0000000 --- a/include/muduo/net/inspect/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -set(inspect_SRCS - Inspector.cc - PerformanceInspector.cc - ProcessInspector.cc - SystemInspector.cc - ) - -add_library(muduo_inspect ${inspect_SRCS}) -target_link_libraries(muduo_inspect muduo_http) - -if(TCMALLOC_INCLUDE_DIR AND TCMALLOC_LIBRARY) - set_target_properties(muduo_inspect PROPERTIES COMPILE_FLAGS "-DHAVE_TCMALLOC") - target_link_libraries(muduo_inspect tcmalloc_and_profiler) -endif() - -install(TARGETS muduo_inspect DESTINATION lib) -set(HEADERS - Inspector.h - ) -install(FILES ${HEADERS} DESTINATION include/muduo/net/inspect) - -if(MUDUO_BUILD_EXAMPLES) -add_executable(inspector_test tests/Inspector_test.cc) -target_link_libraries(inspector_test muduo_inspect) -endif() - diff --git a/include/muduo/net/inspect/Inspector.cc b/include/muduo/net/inspect/Inspector.cc deleted file mode 100644 index 894abd3..0000000 --- a/include/muduo/net/inspect/Inspector.cc +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/inspect/Inspector.h" - -#include "muduo/base/Logging.h" -#include "muduo/base/Thread.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/http/HttpRequest.h" -#include "muduo/net/http/HttpResponse.h" -#include "muduo/net/inspect/ProcessInspector.h" -#include "muduo/net/inspect/PerformanceInspector.h" -#include "muduo/net/inspect/SystemInspector.h" - -//#include -//#include -//#include -//#include -//#include - -using namespace muduo; -using namespace muduo::net; - -namespace -{ -Inspector* g_globalInspector = 0; - -// Looks buggy -std::vector split(const string& str) -{ - std::vector result; - size_t start = 0; - size_t pos = str.find('/'); - while (pos != string::npos) - { - if (pos > start) - { - result.push_back(str.substr(start, pos-start)); - } - start = pos+1; - pos = str.find('/', start); - } - - if (start < str.length()) - { - result.push_back(str.substr(start)); - } - - return result; -} - -} // namespace - -extern char favicon[1743]; - -Inspector::Inspector(EventLoop* loop, - const InetAddress& httpAddr, - const string& name) - : server_(loop, httpAddr, "Inspector:"+name), - processInspector_(new ProcessInspector), - systemInspector_(new SystemInspector) -{ - assert(CurrentThread::isMainThread()); - assert(g_globalInspector == 0); - g_globalInspector = this; - server_.setHttpCallback(std::bind(&Inspector::onRequest, this, _1, _2)); - processInspector_->registerCommands(this); - systemInspector_->registerCommands(this); -#ifdef HAVE_TCMALLOC - performanceInspector_.reset(new PerformanceInspector); - performanceInspector_->registerCommands(this); -#endif - loop->runAfter(0, std::bind(&Inspector::start, this)); // little race condition -} - -Inspector::~Inspector() -{ - assert(CurrentThread::isMainThread()); - g_globalInspector = NULL; -} - -void Inspector::add(const string& module, - const string& command, - const Callback& cb, - const string& help) -{ - MutexLockGuard lock(mutex_); - modules_[module][command] = cb; - helps_[module][command] = help; -} - -void Inspector::remove(const string& module, const string& command) -{ - MutexLockGuard lock(mutex_); - std::map::iterator it = modules_.find(module); - if (it != modules_.end()) - { - it->second.erase(command); - helps_[module].erase(command); - } -} - -void Inspector::start() -{ - server_.start(); -} - -void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) -{ - if (req.path() == "/") - { - string result; - MutexLockGuard lock(mutex_); - for (std::map::const_iterator helpListI = helps_.begin(); - helpListI != helps_.end(); - ++helpListI) - { - const HelpList& list = helpListI->second; - for (const auto& it : list) - { - result += "/"; - result += helpListI->first; - result += "/"; - result += it.first; - size_t len = helpListI->first.size() + it.first.size(); - result += string(len >= 25 ? 1 : 25 - len, ' '); - result += it.second; - result += "\n"; - } - } - resp->setStatusCode(HttpResponse::k200Ok); - resp->setStatusMessage("OK"); - resp->setContentType("text/plain"); - resp->setBody(result); - } - else - { - std::vector result = split(req.path()); - // boost::split(result, req.path(), boost::is_any_of("/")); - //std::copy(result.begin(), result.end(), std::ostream_iterator(std::cout, ", ")); - //std::cout << "\n"; - bool ok = false; - if (result.size() == 0) - { - LOG_DEBUG << req.path(); - } - else if (result.size() == 1) - { - string module = result[0]; - if (module == "favicon.ico") - { - resp->setStatusCode(HttpResponse::k200Ok); - resp->setStatusMessage("OK"); - resp->setContentType("image/png"); - resp->setBody(string(favicon, sizeof favicon)); - - ok = true; - } - else - { - LOG_ERROR << "Unimplemented " << module; - } - } - else - { - string module = result[0]; - MutexLockGuard lock(mutex_); - std::map::const_iterator commListI = modules_.find(module); - if (commListI != modules_.end()) - { - string command = result[1]; - const CommandList& commList = commListI->second; - CommandList::const_iterator it = commList.find(command); - if (it != commList.end()) - { - ArgList args(result.begin()+2, result.end()); - if (it->second) - { - resp->setStatusCode(HttpResponse::k200Ok); - resp->setStatusMessage("OK"); - resp->setContentType("text/plain"); - const Callback& cb = it->second; - resp->setBody(cb(req.method(), args)); - ok = true; - } - } - } - - } - - if (!ok) - { - resp->setStatusCode(HttpResponse::k404NotFound); - resp->setStatusMessage("Not Found"); - } - //resp->setCloseConnection(true); - } -} - -char favicon[1743] = -{ - '\x89', '\x50', '\x4e', '\x47', '\x0d', '\x0a', '\x1a', '\x0a', '\x00', '\x00', - '\x00', '\x0d', '\x49', '\x48', '\x44', '\x52', '\x00', '\x00', '\x00', '\x10', - '\x00', '\x00', '\x00', '\x10', '\x08', '\x06', '\x00', '\x00', '\x00', '\x1f', - '\xf3', '\xff', '\x61', '\x00', '\x00', '\x00', '\x04', '\x73', '\x42', '\x49', - '\x54', '\x08', '\x08', '\x08', '\x08', '\x7c', '\x08', '\x64', '\x88', '\x00', - '\x00', '\x00', '\x09', '\x70', '\x48', '\x59', '\x73', '\x00', '\x00', '\x0b', - '\x12', '\x00', '\x00', '\x0b', '\x12', '\x01', '\xd2', '\xdd', '\x7e', '\xfc', - '\x00', '\x00', '\x00', '\x1c', '\x74', '\x45', '\x58', '\x74', '\x53', '\x6f', - '\x66', '\x74', '\x77', '\x61', '\x72', '\x65', '\x00', '\x41', '\x64', '\x6f', - '\x62', '\x65', '\x20', '\x46', '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', - '\x6b', '\x73', '\x20', '\x43', '\x53', '\x33', '\x98', '\xd6', '\x46', '\x03', - '\x00', '\x00', '\x00', '\x15', '\x74', '\x45', '\x58', '\x74', '\x43', '\x72', - '\x65', '\x61', '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x54', '\x69', '\x6d', - '\x65', '\x00', '\x32', '\x2f', '\x31', '\x37', '\x2f', '\x30', '\x38', '\x20', - '\x9c', '\xaa', '\x58', '\x00', '\x00', '\x04', '\x11', '\x74', '\x45', '\x58', - '\x74', '\x58', '\x4d', '\x4c', '\x3a', '\x63', '\x6f', '\x6d', '\x2e', '\x61', - '\x64', '\x6f', '\x62', '\x65', '\x2e', '\x78', '\x6d', '\x70', '\x00', '\x3c', - '\x3f', '\x78', '\x70', '\x61', '\x63', '\x6b', '\x65', '\x74', '\x20', '\x62', - '\x65', '\x67', '\x69', '\x6e', '\x3d', '\x22', '\x20', '\x20', '\x20', '\x22', - '\x20', '\x69', '\x64', '\x3d', '\x22', '\x57', '\x35', '\x4d', '\x30', '\x4d', - '\x70', '\x43', '\x65', '\x68', '\x69', '\x48', '\x7a', '\x72', '\x65', '\x53', - '\x7a', '\x4e', '\x54', '\x63', '\x7a', '\x6b', '\x63', '\x39', '\x64', '\x22', - '\x3f', '\x3e', '\x0a', '\x3c', '\x78', '\x3a', '\x78', '\x6d', '\x70', '\x6d', - '\x65', '\x74', '\x61', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', - '\x78', '\x3d', '\x22', '\x61', '\x64', '\x6f', '\x62', '\x65', '\x3a', '\x6e', - '\x73', '\x3a', '\x6d', '\x65', '\x74', '\x61', '\x2f', '\x22', '\x20', '\x78', - '\x3a', '\x78', '\x6d', '\x70', '\x74', '\x6b', '\x3d', '\x22', '\x41', '\x64', - '\x6f', '\x62', '\x65', '\x20', '\x58', '\x4d', '\x50', '\x20', '\x43', '\x6f', - '\x72', '\x65', '\x20', '\x34', '\x2e', '\x31', '\x2d', '\x63', '\x30', '\x33', - '\x34', '\x20', '\x34', '\x36', '\x2e', '\x32', '\x37', '\x32', '\x39', '\x37', - '\x36', '\x2c', '\x20', '\x53', '\x61', '\x74', '\x20', '\x4a', '\x61', '\x6e', - '\x20', '\x32', '\x37', '\x20', '\x32', '\x30', '\x30', '\x37', '\x20', '\x32', - '\x32', '\x3a', '\x31', '\x31', '\x3a', '\x34', '\x31', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x22', '\x3e', '\x0a', '\x20', '\x20', - '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x52', '\x44', '\x46', '\x20', - '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x72', '\x64', '\x66', '\x3d', - '\x22', '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x77', '\x77', - '\x77', '\x2e', '\x77', '\x33', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x31', - '\x39', '\x39', '\x39', '\x2f', '\x30', '\x32', '\x2f', '\x32', '\x32', '\x2d', - '\x72', '\x64', '\x66', '\x2d', '\x73', '\x79', '\x6e', '\x74', '\x61', '\x78', - '\x2d', '\x6e', '\x73', '\x23', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x44', '\x65', - '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', '\x20', - '\x72', '\x64', '\x66', '\x3a', '\x61', '\x62', '\x6f', '\x75', '\x74', '\x3d', - '\x22', '\x22', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', - '\x3a', '\x78', '\x61', '\x70', '\x3d', '\x22', '\x68', '\x74', '\x74', '\x70', - '\x3a', '\x2f', '\x2f', '\x6e', '\x73', '\x2e', '\x61', '\x64', '\x6f', '\x62', - '\x65', '\x2e', '\x63', '\x6f', '\x6d', '\x2f', '\x78', '\x61', '\x70', '\x2f', - '\x31', '\x2e', '\x30', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', - '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', - '\x6f', '\x6c', '\x3e', '\x41', '\x64', '\x6f', '\x62', '\x65', '\x20', '\x46', - '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', '\x6b', '\x73', '\x20', '\x43', - '\x53', '\x33', '\x3c', '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', - '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', '\x6f', '\x6c', '\x3e', - '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', - '\x65', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', '\x30', '\x30', '\x38', - '\x2d', '\x30', '\x32', '\x2d', '\x31', '\x37', '\x54', '\x30', '\x32', '\x3a', - '\x33', '\x36', '\x3a', '\x34', '\x35', '\x5a', '\x3c', '\x2f', '\x78', '\x61', - '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x65', '\x44', '\x61', - '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', - '\x64', '\x69', '\x66', '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', - '\x30', '\x30', '\x38', '\x2d', '\x30', '\x33', '\x2d', '\x32', '\x34', '\x54', - '\x31', '\x39', '\x3a', '\x30', '\x30', '\x3a', '\x34', '\x32', '\x5a', '\x3c', - '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', '\x64', '\x69', '\x66', - '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', - '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', - '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x72', - '\x64', '\x66', '\x3a', '\x44', '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', - '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x72', '\x64', '\x66', '\x3a', '\x61', - '\x62', '\x6f', '\x75', '\x74', '\x3d', '\x22', '\x22', '\x0a', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x64', '\x63', '\x3d', '\x22', - '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x70', '\x75', '\x72', - '\x6c', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x64', '\x63', '\x2f', '\x65', - '\x6c', '\x65', '\x6d', '\x65', '\x6e', '\x74', '\x73', '\x2f', '\x31', '\x2e', - '\x31', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x3c', '\x64', '\x63', '\x3a', '\x66', '\x6f', - '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x69', '\x6d', '\x61', '\x67', '\x65', - '\x2f', '\x70', '\x6e', '\x67', '\x3c', '\x2f', '\x64', '\x63', '\x3a', '\x66', - '\x6f', '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x0a', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', - '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', - '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', - '\x3a', '\x52', '\x44', '\x46', '\x3e', '\x0a', '\x3c', '\x2f', '\x78', '\x3a', - '\x78', '\x6d', '\x70', '\x6d', '\x65', '\x74', '\x61', '\x3e', '\x0a', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x0a', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', - '\x20', '\x20', '\x35', '\x1d', '\x52', '\x64', '\x00', '\x00', '\x02', '\x0b', - '\x49', '\x44', '\x41', '\x54', '\x38', '\x8d', '\xa5', '\x93', '\x41', '\x6b', - '\x1a', '\x41', '\x18', '\x86', '\x9f', '\x89', '\x06', '\x23', '\x2e', '\x74', - '\xf5', '\x20', '\x4a', '\x0e', '\x6b', '\x20', '\xe4', '\xe2', '\xa5', '\x78', - '\xc8', '\xa1', '\x78', '\x89', '\x82', '\x17', '\x85', '\x82', '\x82', '\x3d', - '\x26', '\x62', '\x58', '\x72', '\xcd', '\x4f', '\xf1', '\x18', '\x4b', '\x1b', - '\x2f', '\xa5', '\x32', '\xe0', '\xb5', '\x9e', '\x35', '\x1a', '\x58', '\x2f', - '\xe9', '\x0f', '\xe8', '\x65', '\x6d', '\x84', '\xa2', '\x84', '\x2c', '\x0a', - '\x6b', '\x58', '\x62', '\xa7', '\x87', '\x68', '\x68', '\x13', '\xa1', '\xa5', - '\x79', '\xe1', '\x3b', '\x0c', '\xc3', '\xfb', '\xcc', '\x37', '\xef', '\x7c', - '\x23', '\x94', '\x52', '\xbc', '\x44', '\x7e', '\x00', '\x21', '\x04', '\x00', - '\xad', '\x56', '\xcb', '\x18', '\x8f', '\xc7', '\x0d', '\xdb', '\xb6', '\xd3', - '\x8e', '\xe3', '\xf8', '\x83', '\xc1', '\xa0', '\x8a', '\xc7', '\xe3', '\x3f', - '\x12', '\x89', '\x44', '\xb9', '\x5c', '\x2e', '\xf7', '\x56', '\xa6', '\xdf', - '\x0f', '\x15', '\x4a', '\x29', '\x84', '\x10', '\x34', '\x9b', '\xcd', '\x77', - '\x96', '\x65', '\x7d', '\x36', '\x0c', '\x43', '\xe4', '\x72', '\x39', '\xe2', - '\xf1', '\x38', '\xb7', '\xb7', '\xb7', '\xf4', '\xfb', '\x7d', '\x06', '\x83', - '\x01', '\xa9', '\x54', '\xea', '\x43', '\xa5', '\x52', '\x39', '\x7e', '\x0a', - '\x40', '\x29', '\x45', '\xab', '\xd5', '\x32', '\x4e', '\x4f', '\x4f', '\x7f', - '\x4a', '\x29', '\xd5', '\xdd', '\xdd', '\xdd', '\xb3', '\xea', '\xf5', '\x7a', - '\xea', '\xe4', '\xe4', '\x44', '\x49', '\x29', '\xd3', '\x2b', '\xcf', '\xaa', - '\x36', '\x00', '\xc6', '\xe3', '\x71', '\x63', '\x67', '\x67', '\x47', '\xe4', - '\xf3', '\x79', '\x00', '\x3c', '\xcf', '\xa3', '\x50', '\x28', '\xe0', '\xba', - '\x2e', '\x9e', '\xe7', '\x91', '\x4a', '\xa5', '\xd8', '\xdb', '\xdb', '\x63', - '\x34', '\x1a', '\x7d', '\x7c', '\x9a', '\xc1', '\x06', '\x80', '\x6d', '\xdb', - '\xe9', '\x6c', '\x36', '\x8b', '\xcf', '\xe7', '\xc3', '\xf3', '\x3c', '\x5c', - '\xd7', '\x05', '\x60', '\x36', '\x9b', '\xe1', '\xba', '\x2e', '\x8b', '\xc5', - '\x82', '\x4c', '\x26', '\x83', '\x6d', '\xdb', '\xbb', '\x6b', '\x43', '\x74', - '\x1c', '\xc7', '\x1f', '\x8b', '\xc5', '\x00', '\x28', '\x16', '\x8b', '\x8f', - '\x9b', '\xd5', '\x6a', '\x15', '\x00', '\x29', '\x25', '\x9a', '\xa6', '\x31', - '\x9f', '\xcf', '\xc5', '\x5a', '\xc0', '\xd6', '\xd6', '\x96', '\x9a', '\x4c', - '\x26', '\x22', '\x14', '\x0a', '\x21', '\xa5', '\x64', '\x36', '\x9b', '\x51', - '\xad', '\x56', '\xa9', '\xd5', '\x6a', '\x68', '\x9a', '\x06', '\xc0', '\xf5', - '\xf5', '\x35', '\xba', '\xae', '\xdf', '\xaf', '\xbd', '\x82', '\x61', '\x18', - '\xdf', '\x2c', '\xcb', '\x7a', '\x20', '\xfa', '\xfd', '\x04', '\x02', '\x01', - '\x00', '\x34', '\x4d', '\x23', '\x10', '\x08', '\xb0', '\x58', '\x2c', '\xe8', - '\x76', '\xbb', '\x24', '\x12', '\x89', '\x8b', '\xb5', '\x1d', '\x6c', '\x6f', - '\x6f', '\x1f', '\x75', '\x3a', '\x9d', '\x7e', '\x38', '\x1c', '\x26', '\x97', - '\xcb', '\x21', '\x84', '\x40', '\x4a', '\x09', '\xc0', '\xe6', '\xe6', '\x26', - '\xed', '\x76', '\x9b', '\xc9', '\x64', '\xa2', '\xa6', '\xd3', '\xe9', '\x27', - '\x78', '\x98', '\x9b', '\xd5', '\x53', '\x3e', '\xce', '\xc1', '\xf9', '\xf9', - '\xf9', '\xfb', '\xc1', '\x60', '\x70', '\x9c', '\x4c', '\x26', '\xd9', '\xdf', - '\xdf', '\x27', '\x12', '\x89', '\x30', '\x1c', '\x0e', '\xb9', '\xbc', '\xbc', - '\xe4', '\xe6', '\xe6', '\x46', '\xf9', '\x7c', '\xbe', '\x2f', '\xd3', '\xe9', - '\x34', '\x0f', '\x34', '\xea', '\xf5', '\x7a', '\xe5', '\x19', '\x60', '\x19', - '\xd6', '\x9b', '\xd1', '\x68', '\xd4', '\x18', '\x0e', '\x87', '\xbb', '\xf3', - '\xf9', '\x5c', '\xe8', '\xba', '\x7e', '\x6f', '\x18', '\xc6', '\x45', '\x34', - '\x1a', '\x3d', '\x2c', '\x95', '\x4a', '\xdf', '\x4d', '\xd3', '\xbc', '\x02', - '\x5e', '\x03', '\x5f', '\x81', '\x83', '\xb3', '\xb3', '\x33', '\xe7', '\x0f', - '\xc0', '\xdf', '\x64', '\x9a', '\xa6', '\xb1', '\x34', '\xeb', '\x80', '\x03', - '\x1c', '\x6c', '\xfc', '\x93', '\x73', '\xa9', '\x7a', '\xbd', '\x6e', '\x03', - '\x47', '\xcb', '\xa5', '\x0e', '\xbc', '\xe2', '\x7f', '\x7e', '\xa3', '\x69', - '\x9a', '\x87', '\xa6', '\x69', '\xbe', '\x55', '\x4a', '\x3d', '\x64', '\xf0', - '\x12', '\xfd', '\x02', '\x0d', '\x53', '\x06', '\x24', '\x88', '\x3f', '\xe1', - '\x69', '\x00', '\x00', '\x00', '\x00', '\x49', '\x45', '\x4e', '\x44', '\xae', - '\x42', '\x60', '\x82', -}; diff --git a/include/muduo/net/inspect/Inspector.h b/include/muduo/net/inspect/Inspector.h deleted file mode 100644 index 09041d1..0000000 --- a/include/muduo/net/inspect/Inspector.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_INSPECT_INSPECTOR_H -#define MUDUO_NET_INSPECT_INSPECTOR_H - -#include "muduo/base/Mutex.h" -#include "muduo/net/http/HttpRequest.h" -#include "muduo/net/http/HttpServer.h" - -#include - -namespace muduo -{ -namespace net -{ - -class ProcessInspector; -class PerformanceInspector; -class SystemInspector; - -// An internal inspector of the running process, usually a singleton. -// Better to run in a seperated thread, as some method may block for seconds -class Inspector : noncopyable -{ - public: - typedef std::vector ArgList; - typedef std::function Callback; - Inspector(EventLoop* loop, - const InetAddress& httpAddr, - const string& name); - ~Inspector(); - - /// Add a Callback for handling the special uri : /mudule/command - void add(const string& module, - const string& command, - const Callback& cb, - const string& help); - void remove(const string& module, const string& command); - - private: - typedef std::map CommandList; - typedef std::map HelpList; - - void start(); - void onRequest(const HttpRequest& req, HttpResponse* resp); - - HttpServer server_; - std::unique_ptr processInspector_; - std::unique_ptr performanceInspector_; - std::unique_ptr systemInspector_; - MutexLock mutex_; - std::map modules_ GUARDED_BY(mutex_); - std::map helps_ GUARDED_BY(mutex_); -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_INSPECT_INSPECTOR_H diff --git a/include/muduo/net/inspect/PerformanceInspector.cc b/include/muduo/net/inspect/PerformanceInspector.cc deleted file mode 100644 index a0fb9e9..0000000 --- a/include/muduo/net/inspect/PerformanceInspector.cc +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/inspect/PerformanceInspector.h" -#include "muduo/base/FileUtil.h" -#include "muduo/base/LogStream.h" -#include "muduo/base/ProcessInfo.h" - -#include - -#ifdef HAVE_TCMALLOC -#include -#include - -using namespace muduo; -using namespace muduo::net; - -void PerformanceInspector::registerCommands(Inspector* ins) -{ - ins->add("pprof", "heap", PerformanceInspector::heap, "get heap information"); - ins->add("pprof", "growth", PerformanceInspector::growth, "get heap growth information"); - ins->add("pprof", "profile", PerformanceInspector::profile, - "get cpu profiling information. CAUTION: blocking thread for 30 seconds!"); - ins->add("pprof", "cmdline", PerformanceInspector::cmdline, "get command line"); - ins->add("pprof", "memstats", PerformanceInspector::memstats, "get memory stats"); - ins->add("pprof", "memhistogram", PerformanceInspector::memhistogram, "get memory histogram"); - ins->add("pprof", "releasefreememory", PerformanceInspector::releaseFreeMemory, "release free memory"); -} - -string PerformanceInspector::heap(HttpRequest::Method, const Inspector::ArgList&) -{ - std::string result; - MallocExtension::instance()->GetHeapSample(&result); - return string(result.data(), result.size()); -} - -string PerformanceInspector::growth(HttpRequest::Method, const Inspector::ArgList&) -{ - std::string result; - MallocExtension::instance()->GetHeapGrowthStacks(&result); - return string(result.data(), result.size()); -} - -string PerformanceInspector::profile(HttpRequest::Method, const Inspector::ArgList&) -{ - string filename = "/tmp/" + ProcessInfo::procname(); - filename += "."; - filename += ProcessInfo::pidString(); - filename += "."; - filename += Timestamp::now().toString(); - filename += ".profile"; - - string profile; - if (ProfilerStart(filename.c_str())) - { - // FIXME: async - CurrentThread::sleepUsec(30 * 1000 * 1000); - ProfilerStop(); - FileUtil::readFile(filename, 1024*1024, &profile, NULL, NULL); - ::unlink(filename.c_str()); - } - return profile; -} - -string PerformanceInspector::cmdline(HttpRequest::Method, const Inspector::ArgList&) -{ - return ""; -} - -string PerformanceInspector::memstats(HttpRequest::Method, const Inspector::ArgList&) -{ - char buf[1024*64]; - MallocExtension::instance()->GetStats(buf, sizeof buf); - return buf; -} - -string PerformanceInspector::memhistogram(HttpRequest::Method, const Inspector::ArgList&) -{ - int blocks = 0; - size_t total = 0; - int histogram[kMallocHistogramSize] = { 0, }; - - MallocExtension::instance()->MallocMemoryStats(&blocks, &total, histogram); - LogStream s; - s << "blocks " << blocks << "\ntotal " << total << "\n"; - for (int i = 0; i < kMallocHistogramSize; ++i) - s << i << " " << histogram[i] << "\n"; - return s.buffer().toString(); -} - -string PerformanceInspector::releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&) -{ - char buf[256]; - snprintf(buf, sizeof buf, "memory release rate: %f\nAll free memory released.\n", - MallocExtension::instance()->GetMemoryReleaseRate()); - MallocExtension::instance()->ReleaseFreeMemory(); - return buf; -} - -#endif diff --git a/include/muduo/net/inspect/PerformanceInspector.h b/include/muduo/net/inspect/PerformanceInspector.h deleted file mode 100644 index 2416824..0000000 --- a/include/muduo/net/inspect/PerformanceInspector.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H -#define MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H - -#include "muduo/net/inspect/Inspector.h" - -namespace muduo -{ -namespace net -{ - -class PerformanceInspector : noncopyable -{ - public: - void registerCommands(Inspector* ins); - - static string heap(HttpRequest::Method, const Inspector::ArgList&); - static string growth(HttpRequest::Method, const Inspector::ArgList&); - static string profile(HttpRequest::Method, const Inspector::ArgList&); - static string cmdline(HttpRequest::Method, const Inspector::ArgList&); - static string memstats(HttpRequest::Method, const Inspector::ArgList&); - static string memhistogram(HttpRequest::Method, const Inspector::ArgList&); - static string releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&); - - static string symbol(HttpRequest::Method, const Inspector::ArgList&); -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H diff --git a/include/muduo/net/inspect/ProcessInspector.cc b/include/muduo/net/inspect/ProcessInspector.cc deleted file mode 100644 index d89f0ce..0000000 --- a/include/muduo/net/inspect/ProcessInspector.cc +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/inspect/ProcessInspector.h" -#include "muduo/base/FileUtil.h" -#include "muduo/base/ProcessInfo.h" -#include -#include -#include -#include - -using namespace muduo; -using namespace muduo::net; - -namespace muduo -{ -namespace inspect -{ - -string uptime(Timestamp now, Timestamp start, bool showMicroseconds) -{ - char buf[256]; - int64_t age = now.microSecondsSinceEpoch() - start.microSecondsSinceEpoch(); - int seconds = static_cast(age / Timestamp::kMicroSecondsPerSecond); - int days = seconds/86400; - int hours = (seconds % 86400) / 3600; - int minutes = (seconds % 3600) / 60; - if (showMicroseconds) - { - int microseconds = static_cast(age % Timestamp::kMicroSecondsPerSecond); - snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d.%06d", - days, hours, minutes, seconds % 60, microseconds); - } - else - { - snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d", - days, hours, minutes, seconds % 60); - } - return buf; -} - -long getLong(const string& procStatus, const char* key) -{ - long result = 0; - size_t pos = procStatus.find(key); - if (pos != string::npos) - { - result = ::atol(procStatus.c_str() + pos + strlen(key)); - } - return result; -} - -string getProcessName(const string& procStatus) -{ - string result; - size_t pos = procStatus.find("Name:"); - if (pos != string::npos) - { - pos += strlen("Name:"); - while (procStatus[pos] == '\t') - ++pos; - size_t eol = pos; - while (procStatus[eol] != '\n') - ++eol; - result = procStatus.substr(pos, eol-pos); - } - return result; -} - -StringPiece next(StringPiece data) -{ - const char* sp = static_cast(::memchr(data.data(), ' ', data.size())); - if (sp) - { - data.remove_prefix(static_cast(sp+1-data.begin())); - return data; - } - return ""; -} - -ProcessInfo::CpuTime getCpuTime(StringPiece data) -{ - ProcessInfo::CpuTime t; - - for (int i = 0; i < 10; ++i) - { - data = next(data); - } - long utime = strtol(data.data(), NULL, 10); - data = next(data); - long stime = strtol(data.data(), NULL, 10); - const double hz = static_cast(ProcessInfo::clockTicksPerSecond()); - t.userSeconds = static_cast(utime) / hz; - t.systemSeconds = static_cast(stime) / hz; - return t; -} - -int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); - -int stringPrintf(string* out, const char* fmt, ...) -{ - char buf[256]; - va_list args; - va_start(args, fmt); - int ret = vsnprintf(buf, sizeof buf, fmt, args); - va_end(args); - out->append(buf); - return ret; -} - -} // namespace inspect -} // namespace muduo - -using namespace muduo::inspect; - -string ProcessInspector::username_ = ProcessInfo::username(); - -void ProcessInspector::registerCommands(Inspector* ins) -{ - ins->add("proc", "overview", ProcessInspector::overview, "print basic overview"); - ins->add("proc", "pid", ProcessInspector::pid, "print pid"); - ins->add("proc", "status", ProcessInspector::procStatus, "print /proc/self/status"); - // ins->add("proc", "opened_files", ProcessInspector::openedFiles, "count /proc/self/fd"); - ins->add("proc", "threads", ProcessInspector::threads, "list /proc/self/task"); -} - -string ProcessInspector::overview(HttpRequest::Method, const Inspector::ArgList&) -{ - string result; - result.reserve(1024); - Timestamp now = Timestamp::now(); - result += "Page generated at "; - result += now.toFormattedString(); - result += " (UTC)\nStarted at "; - result += ProcessInfo::startTime().toFormattedString(); - result += " (UTC), up for "; - result += uptime(now, ProcessInfo::startTime(), true/* show microseconds */); - result += "\n"; - - string procStatus = ProcessInfo::procStatus(); - result += getProcessName(procStatus); - result += " ("; - result += ProcessInfo::exePath(); - result += ") running as "; - result += username_; - result += " on "; - result += ProcessInfo::hostname(); // cache ? - result += "\n"; - - if (ProcessInfo::isDebugBuild()) - { - result += "WARNING: debug build!\n"; - } - - stringPrintf(&result, "pid %d, num of threads %ld, bits %zd\n", - ProcessInfo::pid(), getLong(procStatus, "Threads:"), CHAR_BIT * sizeof(void*)); - - result += "Virtual memory: "; - stringPrintf(&result, "%.3f MiB, ", - static_cast(getLong(procStatus, "VmSize:")) / 1024.0); - - result += "RSS memory: "; - stringPrintf(&result, "%.3f MiB\n", - static_cast(getLong(procStatus, "VmRSS:")) / 1024.0); - - // FIXME: VmData: - - stringPrintf(&result, "Opened files: %d, limit: %d\n", - ProcessInfo::openedFiles(), ProcessInfo::maxOpenFiles()); - - // string procStat = ProcessInfo::procStat(); - - /* - stringPrintf(&result, "ppid %ld\n", getStatField(procStat, 0)); - stringPrintf(&result, "pgid %ld\n", getStatField(procStat, 1)); - */ - - ProcessInfo::CpuTime t = ProcessInfo::cpuTime(); - stringPrintf(&result, "User time: %12.3fs\nSys time: %12.3fs\n", - t.userSeconds, t.systemSeconds); - - // FIXME: add context switches - - return result; -} - -string ProcessInspector::pid(HttpRequest::Method, const Inspector::ArgList&) -{ - char buf[32]; - snprintf(buf, sizeof buf, "%d", ProcessInfo::pid()); - return buf; -} - -string ProcessInspector::procStatus(HttpRequest::Method, const Inspector::ArgList&) -{ - return ProcessInfo::procStatus(); -} - -string ProcessInspector::openedFiles(HttpRequest::Method, const Inspector::ArgList&) -{ - char buf[32]; - snprintf(buf, sizeof buf, "%d", ProcessInfo::openedFiles()); - return buf; -} - -string ProcessInspector::threads(HttpRequest::Method, const Inspector::ArgList&) -{ - std::vector threads = ProcessInfo::threads(); - string result = " TID NAME S User Time System Time\n"; - result.reserve(threads.size() * 64); - string stat; - for (pid_t tid : threads) - { - char buf[256]; - snprintf(buf, sizeof buf, "/proc/%d/task/%d/stat", ProcessInfo::pid(), tid); - if (FileUtil::readFile(buf, 65536, &stat) == 0) - { - StringPiece name = ProcessInfo::procname(stat); - const char* rp = name.end(); - assert(*rp == ')'); - const char* state = rp + 2; - *const_cast(rp) = '\0'; // don't do this at home - StringPiece data(stat); - data.remove_prefix(static_cast(state - data.data() + 2)); - ProcessInfo::CpuTime t = getCpuTime(data); - snprintf(buf, sizeof buf, "%5d %-16s %c %12.3f %12.3f\n", - tid, name.data(), *state, t.userSeconds, t.systemSeconds); - result += buf; - } - } - return result; -} - diff --git a/include/muduo/net/inspect/ProcessInspector.h b/include/muduo/net/inspect/ProcessInspector.h deleted file mode 100644 index f1df478..0000000 --- a/include/muduo/net/inspect/ProcessInspector.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_INSPECT_PROCESSINSPECTOR_H -#define MUDUO_NET_INSPECT_PROCESSINSPECTOR_H - -#include "muduo/net/inspect/Inspector.h" - -namespace muduo -{ -namespace net -{ - -class ProcessInspector : noncopyable -{ - public: - void registerCommands(Inspector* ins); - - static string overview(HttpRequest::Method, const Inspector::ArgList&); - static string pid(HttpRequest::Method, const Inspector::ArgList&); - static string procStatus(HttpRequest::Method, const Inspector::ArgList&); - static string openedFiles(HttpRequest::Method, const Inspector::ArgList&); - static string threads(HttpRequest::Method, const Inspector::ArgList&); - - static string username_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_INSPECT_PROCESSINSPECTOR_H diff --git a/include/muduo/net/inspect/SystemInspector.cc b/include/muduo/net/inspect/SystemInspector.cc deleted file mode 100644 index fb45e76..0000000 --- a/include/muduo/net/inspect/SystemInspector.cc +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2014, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// - -#include "muduo/net/inspect/SystemInspector.h" -#include "muduo/base/FileUtil.h" - -#include - -using namespace muduo; -using namespace muduo::net; - -namespace muduo -{ -namespace inspect -{ -string uptime(Timestamp now, Timestamp start, bool showMicroseconds); -long getLong(const string& content, const char* key); -int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); -} -} - -using namespace muduo::inspect; - -void SystemInspector::registerCommands(Inspector* ins) -{ - ins->add("sys", "overview", SystemInspector::overview, "print system overview"); - ins->add("sys", "loadavg", SystemInspector::loadavg, "print /proc/loadavg"); - ins->add("sys", "version", SystemInspector::version, "print /proc/version"); - ins->add("sys", "cpuinfo", SystemInspector::cpuinfo, "print /proc/cpuinfo"); - ins->add("sys", "meminfo", SystemInspector::meminfo, "print /proc/meminfo"); - ins->add("sys", "stat", SystemInspector::stat, "print /proc/stat"); -} - -string SystemInspector::loadavg(HttpRequest::Method, const Inspector::ArgList&) -{ - string loadavg; - FileUtil::readFile("/proc/loadavg", 65536, &loadavg); - return loadavg; -} - -string SystemInspector::version(HttpRequest::Method, const Inspector::ArgList&) -{ - string version; - FileUtil::readFile("/proc/version", 65536, &version); - return version; -} - -string SystemInspector::cpuinfo(HttpRequest::Method, const Inspector::ArgList&) -{ - string cpuinfo; - FileUtil::readFile("/proc/cpuinfo", 65536, &cpuinfo); - return cpuinfo; -} - -string SystemInspector::meminfo(HttpRequest::Method, const Inspector::ArgList&) -{ - string meminfo; - FileUtil::readFile("/proc/meminfo", 65536, &meminfo); - return meminfo; -} - -string SystemInspector::stat(HttpRequest::Method, const Inspector::ArgList&) -{ - string stat; - FileUtil::readFile("/proc/stat", 65536, &stat); - return stat; -} - -string SystemInspector::overview(HttpRequest::Method, const Inspector::ArgList&) -{ - string result; - result.reserve(1024); - Timestamp now = Timestamp::now(); - result += "Page generated at "; - result += now.toFormattedString(); - result += " (UTC)\n"; - // Hardware and OS - { - struct utsname un; - if (::uname(&un) == 0) - { - stringPrintf(&result, "Hostname: %s\n", un.nodename); - stringPrintf(&result, "Machine: %s\n", un.machine); - stringPrintf(&result, "OS: %s %s %s\n", un.sysname, un.release, un.version); - } - } - string stat; - FileUtil::readFile("/proc/stat", 65536, &stat); - Timestamp bootTime(Timestamp::kMicroSecondsPerSecond * getLong(stat, "btime ")); - result += "Boot time: "; - result += bootTime.toFormattedString(false /* show microseconds */); - result += " (UTC)\n"; - result += "Up time: "; - result += uptime(now, bootTime, false /* show microseconds */); - result += "\n"; - - // CPU load - { - string loadavg; - FileUtil::readFile("/proc/loadavg", 65536, &loadavg); - stringPrintf(&result, "Processes created: %ld\n", getLong(stat, "processes ")); - stringPrintf(&result, "Loadavg: %s\n", loadavg.c_str()); - } - - // Memory - { - string meminfo; - FileUtil::readFile("/proc/meminfo", 65536, &meminfo); - long total_kb = getLong(meminfo, "MemTotal:"); - long free_kb = getLong(meminfo, "MemFree:"); - long buffers_kb = getLong(meminfo, "Buffers:"); - long cached_kb = getLong(meminfo, "Cached:"); - - stringPrintf(&result, "Total Memory: %6ld MiB\n", total_kb / 1024); - stringPrintf(&result, "Free Memory: %6ld MiB\n", free_kb / 1024); - stringPrintf(&result, "Buffers: %6ld MiB\n", buffers_kb / 1024); - stringPrintf(&result, "Cached: %6ld MiB\n", cached_kb / 1024); - stringPrintf(&result, "Real Used: %6ld MiB\n", (total_kb - free_kb - buffers_kb - cached_kb) / 1024); - stringPrintf(&result, "Real Free: %6ld MiB\n", (free_kb + buffers_kb + cached_kb) / 1024); - - // Swap - } - // Disk - // Network - return result; -} diff --git a/include/muduo/net/inspect/SystemInspector.h b/include/muduo/net/inspect/SystemInspector.h deleted file mode 100644 index 8f2a604..0000000 --- a/include/muduo/net/inspect/SystemInspector.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H -#define MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H - -#include "muduo/net/inspect/Inspector.h" - -namespace muduo -{ -namespace net -{ - -class SystemInspector : noncopyable -{ - public: - void registerCommands(Inspector* ins); - - static string overview(HttpRequest::Method, const Inspector::ArgList&); - static string loadavg(HttpRequest::Method, const Inspector::ArgList&); - static string version(HttpRequest::Method, const Inspector::ArgList&); - static string cpuinfo(HttpRequest::Method, const Inspector::ArgList&); - static string meminfo(HttpRequest::Method, const Inspector::ArgList&); - static string stat(HttpRequest::Method, const Inspector::ArgList&); -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H diff --git a/include/muduo/net/inspect/tests/BUILD.bazel b/include/muduo/net/inspect/tests/BUILD.bazel deleted file mode 100644 index e7f0ca7..0000000 --- a/include/muduo/net/inspect/tests/BUILD.bazel +++ /dev/null @@ -1,7 +0,0 @@ -cc_binary( - name = "inspector", - srcs = ["Inspector_test.cc"], - deps = [ - "//muduo/net/inspect", - ], -) diff --git a/include/muduo/net/inspect/tests/Inspector_test.cc b/include/muduo/net/inspect/tests/Inspector_test.cc deleted file mode 100644 index 20025ff..0000000 --- a/include/muduo/net/inspect/tests/Inspector_test.cc +++ /dev/null @@ -1,15 +0,0 @@ -#include "muduo/net/inspect/Inspector.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/EventLoopThread.h" - -using namespace muduo; -using namespace muduo::net; - -int main() -{ - EventLoop loop; - EventLoopThread t; - Inspector ins(t.startLoop(), InetAddress(12345), "test"); - loop.loop(); -} - diff --git a/include/muduo/net/poller/DefaultPoller.cc b/include/muduo/net/poller/DefaultPoller.cc deleted file mode 100644 index 5ea0d03..0000000 --- a/include/muduo/net/poller/DefaultPoller.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/Poller.h" -#include "muduo/net/poller/PollPoller.h" -#include "muduo/net/poller/EPollPoller.h" - -#include - -using namespace muduo::net; - -Poller* Poller::newDefaultPoller(EventLoop* loop) -{ - if (::getenv("MUDUO_USE_POLL")) - { - return new PollPoller(loop); - } - else - { - return new EPollPoller(loop); - } -} diff --git a/include/muduo/net/poller/EPollPoller.cc b/include/muduo/net/poller/EPollPoller.cc deleted file mode 100644 index b2f913a..0000000 --- a/include/muduo/net/poller/EPollPoller.cc +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/poller/EPollPoller.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/Channel.h" - -#include -#include -#include -#include -#include - -using namespace muduo; -using namespace muduo::net; - -// On Linux, the constants of poll(2) and epoll(4) -// are expected to be the same. -static_assert(EPOLLIN == POLLIN, "epoll uses same flag values as poll"); -static_assert(EPOLLPRI == POLLPRI, "epoll uses same flag values as poll"); -static_assert(EPOLLOUT == POLLOUT, "epoll uses same flag values as poll"); -static_assert(EPOLLRDHUP == POLLRDHUP, "epoll uses same flag values as poll"); -static_assert(EPOLLERR == POLLERR, "epoll uses same flag values as poll"); -static_assert(EPOLLHUP == POLLHUP, "epoll uses same flag values as poll"); - -namespace -{ -const int kNew = -1; -const int kAdded = 1; -const int kDeleted = 2; -} - -EPollPoller::EPollPoller(EventLoop* loop) - : Poller(loop), - epollfd_(::epoll_create1(EPOLL_CLOEXEC)), - events_(kInitEventListSize) -{ - if (epollfd_ < 0) - { - LOG_SYSFATAL << "EPollPoller::EPollPoller"; - } -} - -EPollPoller::~EPollPoller() -{ - ::close(epollfd_); -} - -Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) -{ - LOG_TRACE << "fd total count " << channels_.size(); - int numEvents = ::epoll_wait(epollfd_, - &*events_.begin(), - static_cast(events_.size()), - timeoutMs); - int savedErrno = errno; - Timestamp now(Timestamp::now()); - if (numEvents > 0) - { - LOG_TRACE << numEvents << " events happened"; - fillActiveChannels(numEvents, activeChannels); - if (implicit_cast(numEvents) == events_.size()) - { - events_.resize(events_.size()*2); - } - } - else if (numEvents == 0) - { - LOG_TRACE << "nothing happened"; - } - else - { - // error happens, log uncommon ones - if (savedErrno != EINTR) - { - errno = savedErrno; - LOG_SYSERR << "EPollPoller::poll()"; - } - } - return now; -} - -void EPollPoller::fillActiveChannels(int numEvents, - ChannelList* activeChannels) const -{ - assert(implicit_cast(numEvents) <= events_.size()); - for (int i = 0; i < numEvents; ++i) - { - Channel* channel = static_cast(events_[i].data.ptr); -#ifndef NDEBUG - int fd = channel->fd(); - ChannelMap::const_iterator it = channels_.find(fd); - assert(it != channels_.end()); - assert(it->second == channel); -#endif - channel->set_revents(events_[i].events); - activeChannels->push_back(channel); - } -} - -void EPollPoller::updateChannel(Channel* channel) -{ - Poller::assertInLoopThread(); - const int index = channel->index(); - LOG_TRACE << "fd = " << channel->fd() - << " events = " << channel->events() << " index = " << index; - if (index == kNew || index == kDeleted) - { - // a new one, add with EPOLL_CTL_ADD - int fd = channel->fd(); - if (index == kNew) - { - assert(channels_.find(fd) == channels_.end()); - channels_[fd] = channel; - } - else // index == kDeleted - { - assert(channels_.find(fd) != channels_.end()); - assert(channels_[fd] == channel); - } - - channel->set_index(kAdded); - update(EPOLL_CTL_ADD, channel); - } - else - { - // update existing one with EPOLL_CTL_MOD/DEL - int fd = channel->fd(); - (void)fd; - assert(channels_.find(fd) != channels_.end()); - assert(channels_[fd] == channel); - assert(index == kAdded); - if (channel->isNoneEvent()) - { - update(EPOLL_CTL_DEL, channel); - channel->set_index(kDeleted); - } - else - { - update(EPOLL_CTL_MOD, channel); - } - } -} - -void EPollPoller::removeChannel(Channel* channel) -{ - Poller::assertInLoopThread(); - int fd = channel->fd(); - LOG_TRACE << "fd = " << fd; - assert(channels_.find(fd) != channels_.end()); - assert(channels_[fd] == channel); - assert(channel->isNoneEvent()); - int index = channel->index(); - assert(index == kAdded || index == kDeleted); - size_t n = channels_.erase(fd); - (void)n; - assert(n == 1); - - if (index == kAdded) - { - update(EPOLL_CTL_DEL, channel); - } - channel->set_index(kNew); -} - -void EPollPoller::update(int operation, Channel* channel) -{ - struct epoll_event event; - memZero(&event, sizeof event); - event.events = channel->events(); - event.data.ptr = channel; - int fd = channel->fd(); - LOG_TRACE << "epoll_ctl op = " << operationToString(operation) - << " fd = " << fd << " event = { " << channel->eventsToString() << " }"; - if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) - { - if (operation == EPOLL_CTL_DEL) - { - LOG_SYSERR << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; - } - else - { - LOG_SYSFATAL << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; - } - } -} - -const char* EPollPoller::operationToString(int op) -{ - switch (op) - { - case EPOLL_CTL_ADD: - return "ADD"; - case EPOLL_CTL_DEL: - return "DEL"; - case EPOLL_CTL_MOD: - return "MOD"; - default: - assert(false && "ERROR op"); - return "Unknown Operation"; - } -} diff --git a/include/muduo/net/poller/EPollPoller.h b/include/muduo/net/poller/EPollPoller.h deleted file mode 100644 index c112f18..0000000 --- a/include/muduo/net/poller/EPollPoller.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H -#define MUDUO_NET_POLLER_EPOLLPOLLER_H - -#include "muduo/net/Poller.h" - -#include - -struct epoll_event; - -namespace muduo -{ -namespace net -{ - -/// -/// IO Multiplexing with epoll(4). -/// -class EPollPoller : public Poller -{ - public: - EPollPoller(EventLoop* loop); - ~EPollPoller() override; - - Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; - void updateChannel(Channel* channel) override; - void removeChannel(Channel* channel) override; - - private: - static const int kInitEventListSize = 16; - - static const char* operationToString(int op); - - void fillActiveChannels(int numEvents, - ChannelList* activeChannels) const; - void update(int operation, Channel* channel); - - typedef std::vector EventList; - - int epollfd_; - EventList events_; -}; - -} // namespace net -} // namespace muduo -#endif // MUDUO_NET_POLLER_EPOLLPOLLER_H diff --git a/include/muduo/net/poller/PollPoller.cc b/include/muduo/net/poller/PollPoller.cc deleted file mode 100644 index 7933079..0000000 --- a/include/muduo/net/poller/PollPoller.cc +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/poller/PollPoller.h" - -#include "muduo/base/Logging.h" -#include "muduo/base/Types.h" -#include "muduo/net/Channel.h" - -#include -#include -#include - -using namespace muduo; -using namespace muduo::net; - -PollPoller::PollPoller(EventLoop* loop) - : Poller(loop) -{ -} - -PollPoller::~PollPoller() = default; - -Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) -{ - // XXX pollfds_ shouldn't change - int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); - int savedErrno = errno; - Timestamp now(Timestamp::now()); - if (numEvents > 0) - { - LOG_TRACE << numEvents << " events happened"; - fillActiveChannels(numEvents, activeChannels); - } - else if (numEvents == 0) - { - LOG_TRACE << " nothing happened"; - } - else - { - if (savedErrno != EINTR) - { - errno = savedErrno; - LOG_SYSERR << "PollPoller::poll()"; - } - } - return now; -} - -void PollPoller::fillActiveChannels(int numEvents, - ChannelList* activeChannels) const -{ - for (PollFdList::const_iterator pfd = pollfds_.begin(); - pfd != pollfds_.end() && numEvents > 0; ++pfd) - { - if (pfd->revents > 0) - { - --numEvents; - ChannelMap::const_iterator ch = channels_.find(pfd->fd); - assert(ch != channels_.end()); - Channel* channel = ch->second; - assert(channel->fd() == pfd->fd); - channel->set_revents(pfd->revents); - // pfd->revents = 0; - activeChannels->push_back(channel); - } - } -} - -void PollPoller::updateChannel(Channel* channel) -{ - Poller::assertInLoopThread(); - LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); - if (channel->index() < 0) - { - // a new one, add to pollfds_ - assert(channels_.find(channel->fd()) == channels_.end()); - struct pollfd pfd; - pfd.fd = channel->fd(); - pfd.events = static_cast(channel->events()); - pfd.revents = 0; - pollfds_.push_back(pfd); - int idx = static_cast(pollfds_.size())-1; - channel->set_index(idx); - channels_[pfd.fd] = channel; - } - else - { - // update existing one - assert(channels_.find(channel->fd()) != channels_.end()); - assert(channels_[channel->fd()] == channel); - int idx = channel->index(); - assert(0 <= idx && idx < static_cast(pollfds_.size())); - struct pollfd& pfd = pollfds_[idx]; - assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); - pfd.fd = channel->fd(); - pfd.events = static_cast(channel->events()); - pfd.revents = 0; - if (channel->isNoneEvent()) - { - // ignore this pollfd - pfd.fd = -channel->fd()-1; - } - } -} - -void PollPoller::removeChannel(Channel* channel) -{ - Poller::assertInLoopThread(); - LOG_TRACE << "fd = " << channel->fd(); - assert(channels_.find(channel->fd()) != channels_.end()); - assert(channels_[channel->fd()] == channel); - assert(channel->isNoneEvent()); - int idx = channel->index(); - assert(0 <= idx && idx < static_cast(pollfds_.size())); - const struct pollfd& pfd = pollfds_[idx]; (void)pfd; - assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); - size_t n = channels_.erase(channel->fd()); - assert(n == 1); (void)n; - if (implicit_cast(idx) == pollfds_.size()-1) - { - pollfds_.pop_back(); - } - else - { - int channelAtEnd = pollfds_.back().fd; - iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); - if (channelAtEnd < 0) - { - channelAtEnd = -channelAtEnd-1; - } - channels_[channelAtEnd]->set_index(idx); - pollfds_.pop_back(); - } -} - diff --git a/include/muduo/net/poller/PollPoller.h b/include/muduo/net/poller/PollPoller.h deleted file mode 100644 index 4657534..0000000 --- a/include/muduo/net/poller/PollPoller.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is an internal header file, you should not include this. - -#ifndef MUDUO_NET_POLLER_POLLPOLLER_H -#define MUDUO_NET_POLLER_POLLPOLLER_H - -#include "muduo/net/Poller.h" - -#include - -struct pollfd; - -namespace muduo -{ -namespace net -{ - -/// -/// IO Multiplexing with poll(2). -/// -class PollPoller : public Poller -{ - public: - - PollPoller(EventLoop* loop); - ~PollPoller() override; - - Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; - void updateChannel(Channel* channel) override; - void removeChannel(Channel* channel) override; - - private: - void fillActiveChannels(int numEvents, - ChannelList* activeChannels) const; - - typedef std::vector PollFdList; - PollFdList pollfds_; -}; - -} // namespace net -} // namespace muduo -#endif // MUDUO_NET_POLLER_POLLPOLLER_H diff --git a/include/muduo/net/protobuf/BufferStream.h b/include/muduo/net/protobuf/BufferStream.h deleted file mode 100644 index 322bc44..0000000 --- a/include/muduo/net/protobuf/BufferStream.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. -#pragma once -#include "muduo/net/Buffer.h" -#include -namespace muduo -{ -namespace net -{ - -// FIXME: -// class BufferInputStream : google::protobuf::io::ZeroCopyInputStream -// { -// }; - -class BufferOutputStream : public google::protobuf::io::ZeroCopyOutputStream -{ - public: - BufferOutputStream(Buffer* buf) - : buffer_(CHECK_NOTNULL(buf)), - originalSize_(buffer_->readableBytes()) - { - } - - virtual bool Next(void** data, int* size) // override - { - buffer_->ensureWritableBytes(4096); - *data = buffer_->beginWrite(); - *size = static_cast(buffer_->writableBytes()); - buffer_->hasWritten(*size); - return true; - } - - virtual void BackUp(int count) // override - { - buffer_->unwrite(count); - } - - virtual int64_t ByteCount() const // override - { - return buffer_->readableBytes() - originalSize_; - } - - private: - Buffer* buffer_; - size_t originalSize_; -}; - -} -} diff --git a/include/muduo/net/protobuf/CMakeLists.txt b/include/muduo/net/protobuf/CMakeLists.txt deleted file mode 100644 index a7e49d9..0000000 --- a/include/muduo/net/protobuf/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_library(muduo_protobuf_codec ProtobufCodecLite.cc) -set_target_properties(muduo_protobuf_codec PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") -target_link_libraries(muduo_protobuf_codec muduo_net protobuf z) - -#add_library(muduo_protobuf_codec_cpp11 ProtobufCodecLite.cc) -#set_target_properties(muduo_protobuf_codec_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") -#target_link_libraries(muduo_protobuf_codec_cpp11 muduo_net_cpp11 protobuf z) - - -install(TARGETS muduo_protobuf_codec DESTINATION lib) -#install(TARGETS muduo_protobuf_codec_cpp11 DESTINATION lib) - -file(GLOB HEADERS "*.h") -install(FILES ${HEADERS} DESTINATION include/muduo/net/protobuf) - diff --git a/include/muduo/net/protobuf/ProtobufCodecLite.cc b/include/muduo/net/protobuf/ProtobufCodecLite.cc deleted file mode 100644 index 9d406ee..0000000 --- a/include/muduo/net/protobuf/ProtobufCodecLite.cc +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/protobuf/ProtobufCodecLite.h" -// #include - -#include "muduo/base/Logging.h" -#include "muduo/net/Endian.h" -#include "muduo/net/TcpConnection.h" -#include "muduo/net/protorpc/google-inl.h" - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -namespace -{ - int ProtobufVersionCheck() - { - GOOGLE_PROTOBUF_VERIFY_VERSION; - return 0; - } - int __attribute__ ((unused)) dummy = ProtobufVersionCheck(); -} - -void ProtobufCodecLite::send(const TcpConnectionPtr& conn, - const ::google::protobuf::Message& message) -{ - // FIXME: serialize to TcpConnection::outputBuffer() - muduo::net::Buffer buf; - fillEmptyBuffer(&buf, message); - conn->send(&buf); -} - -void ProtobufCodecLite::fillEmptyBuffer(muduo::net::Buffer* buf, - const google::protobuf::Message& message) -{ - assert(buf->readableBytes() == 0); - // FIXME: can we move serialization & checksum to other thread? - buf->append(tag_); - - int byte_size = serializeToBuffer(message, buf); - - int32_t checkSum = checksum(buf->peek(), static_cast(buf->readableBytes())); - buf->appendInt32(checkSum); - assert(buf->readableBytes() == tag_.size() + byte_size + kChecksumLen); (void) byte_size; - int32_t len = sockets::hostToNetwork32(static_cast(buf->readableBytes())); - buf->prepend(&len, sizeof len); -} - -void ProtobufCodecLite::onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime) -{ - while (buf->readableBytes() >= static_cast(kMinMessageLen+kHeaderLen)) - { - const int32_t len = buf->peekInt32(); - if (len > kMaxMessageLen || len < kMinMessageLen) - { - errorCallback_(conn, buf, receiveTime, kInvalidLength); - break; - } - else if (buf->readableBytes() >= implicit_cast(kHeaderLen+len)) - { - if (rawCb_ && !rawCb_(conn, StringPiece(buf->peek(), kHeaderLen+len), receiveTime)) - { - buf->retrieve(kHeaderLen+len); - continue; - } - MessagePtr message(prototype_->New()); - // FIXME: can we move deserialization & callback to other thread? - ErrorCode errorCode = parse(buf->peek()+kHeaderLen, len, message.get()); - if (errorCode == kNoError) - { - // FIXME: try { } catch (...) { } - messageCallback_(conn, message, receiveTime); - buf->retrieve(kHeaderLen+len); - } - else - { - errorCallback_(conn, buf, receiveTime, errorCode); - break; - } - } - else - { - break; - } - } -} - -bool ProtobufCodecLite::parseFromBuffer(StringPiece buf, google::protobuf::Message* message) -{ - return message->ParseFromArray(buf.data(), buf.size()); -} - -int ProtobufCodecLite::serializeToBuffer(const google::protobuf::Message& message, Buffer* buf) -{ - // TODO: use BufferOutputStream - // BufferOutputStream os(buf); - // message.SerializeToZeroCopyStream(&os); - // return static_cast(os.ByteCount()); - - // code copied from MessageLite::SerializeToArray() and MessageLite::SerializePartialToArray(). - GOOGLE_DCHECK(message.IsInitialized()) << InitializationErrorMessage("serialize", message); - - /** - * 'ByteSize()' of message is deprecated in Protocol Buffers v3.4.0 firstly. But, till to v3.11.0, it just getting start to be marked by '__attribute__((deprecated()))'. - * So, here, v3.9.2 is selected as maximum version using 'ByteSize()' to avoid potential effect for previous muduo code/projects as far as possible. - * Note: All information above just INFER from - * 1) https://github.com/protocolbuffers/protobuf/releases/tag/v3.4.0 - * 2) MACRO in file 'include/google/protobuf/port_def.inc'. eg. '#define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))'. - * In addition, usage of 'ToIntSize()' comes from Impl of ByteSize() in new version's Protocol Buffers. - */ - - #if GOOGLE_PROTOBUF_VERSION > 3009002 - int byte_size = google::protobuf::internal::ToIntSize(message.ByteSizeLong()); - #else - int byte_size = message.ByteSize(); - #endif - buf->ensureWritableBytes(byte_size + kChecksumLen); - - uint8_t* start = reinterpret_cast(buf->beginWrite()); - uint8_t* end = message.SerializeWithCachedSizesToArray(start); - if (end - start != byte_size) - { - #if GOOGLE_PROTOBUF_VERSION > 3009002 - ByteSizeConsistencyError(byte_size, google::protobuf::internal::ToIntSize(message.ByteSizeLong()), static_cast(end - start)); - #else - ByteSizeConsistencyError(byte_size, message.ByteSize(), static_cast(end - start)); - #endif - } - buf->hasWritten(byte_size); - return byte_size; -} - -namespace -{ - const string kNoErrorStr = "NoError"; - const string kInvalidLengthStr = "InvalidLength"; - const string kCheckSumErrorStr = "CheckSumError"; - const string kInvalidNameLenStr = "InvalidNameLen"; - const string kUnknownMessageTypeStr = "UnknownMessageType"; - const string kParseErrorStr = "ParseError"; - const string kUnknownErrorStr = "UnknownError"; -} - -const string& ProtobufCodecLite::errorCodeToString(ErrorCode errorCode) -{ - switch (errorCode) - { - case kNoError: - return kNoErrorStr; - case kInvalidLength: - return kInvalidLengthStr; - case kCheckSumError: - return kCheckSumErrorStr; - case kInvalidNameLen: - return kInvalidNameLenStr; - case kUnknownMessageType: - return kUnknownMessageTypeStr; - case kParseError: - return kParseErrorStr; - default: - return kUnknownErrorStr; - } -} - -void ProtobufCodecLite::defaultErrorCallback(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp, - ErrorCode errorCode) -{ - LOG_ERROR << "ProtobufCodecLite::defaultErrorCallback - " << errorCodeToString(errorCode); - if (conn && conn->connected()) - { - conn->shutdown(); - } -} - -int32_t ProtobufCodecLite::asInt32(const char* buf) -{ - int32_t be32 = 0; - ::memcpy(&be32, buf, sizeof(be32)); - return sockets::networkToHost32(be32); -} - -int32_t ProtobufCodecLite::checksum(const void* buf, int len) -{ - return static_cast( - ::adler32(1, static_cast(buf), len)); -} - -bool ProtobufCodecLite::validateChecksum(const char* buf, int len) -{ - // check sum - int32_t expectedCheckSum = asInt32(buf + len - kChecksumLen); - int32_t checkSum = checksum(buf, len - kChecksumLen); - return checkSum == expectedCheckSum; -} - -ProtobufCodecLite::ErrorCode ProtobufCodecLite::parse(const char* buf, - int len, - ::google::protobuf::Message* message) -{ - ErrorCode error = kNoError; - - if (validateChecksum(buf, len)) - { - if (memcmp(buf, tag_.data(), tag_.size()) == 0) - { - // parse from buffer - const char* data = buf + tag_.size(); - int32_t dataLen = len - kChecksumLen - static_cast(tag_.size()); - if (parseFromBuffer(StringPiece(data, dataLen), message)) - { - error = kNoError; - } - else - { - error = kParseError; - } - } - else - { - error = kUnknownMessageType; - } - } - else - { - error = kCheckSumError; - } - - return error; -} - diff --git a/include/muduo/net/protobuf/ProtobufCodecLite.h b/include/muduo/net/protobuf/ProtobufCodecLite.h deleted file mode 100644 index 134ee7b..0000000 --- a/include/muduo/net/protobuf/ProtobufCodecLite.h +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -// For Protobuf codec supporting multiple message types, check -// examples/protobuf/codec - -#ifndef MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H -#define MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H - -#include "muduo/base/noncopyable.h" -#include "muduo/base/StringPiece.h" -#include "muduo/base/Timestamp.h" -#include "muduo/net/Callbacks.h" - -#include -#include - -namespace google -{ -namespace protobuf -{ -class Message; -} -} - -namespace muduo -{ -namespace net -{ - -typedef std::shared_ptr MessagePtr; - -// wire format -// -// Field Length Content -// -// size 4-byte M+N+4 -// tag M-byte could be "RPC0", etc. -// payload N-byte -// checksum 4-byte adler32 of tag+payload -// -// This is an internal class, you should use ProtobufCodecT instead. -class ProtobufCodecLite : noncopyable -{ - public: - const static int kHeaderLen = sizeof(int32_t); - const static int kChecksumLen = sizeof(int32_t); - const static int kMaxMessageLen = 64*1024*1024; // same as codec_stream.h kDefaultTotalBytesLimit - - enum ErrorCode - { - kNoError = 0, - kInvalidLength, - kCheckSumError, - kInvalidNameLen, - kUnknownMessageType, - kParseError, - }; - - // return false to stop parsing protobuf message - typedef std::function RawMessageCallback; - - typedef std::function ProtobufMessageCallback; - - typedef std::function ErrorCallback; - - ProtobufCodecLite(const ::google::protobuf::Message* prototype, - StringPiece tagArg, - const ProtobufMessageCallback& messageCb, - const RawMessageCallback& rawCb = RawMessageCallback(), - const ErrorCallback& errorCb = defaultErrorCallback) - : prototype_(prototype), - tag_(tagArg.as_string()), - messageCallback_(messageCb), - rawCb_(rawCb), - errorCallback_(errorCb), - kMinMessageLen(tagArg.size() + kChecksumLen) - { - } - - virtual ~ProtobufCodecLite() = default; - - const string& tag() const { return tag_; } - - void send(const TcpConnectionPtr& conn, - const ::google::protobuf::Message& message); - - void onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime); - - virtual bool parseFromBuffer(StringPiece buf, google::protobuf::Message* message); - virtual int serializeToBuffer(const google::protobuf::Message& message, Buffer* buf); - - static const string& errorCodeToString(ErrorCode errorCode); - - // public for unit tests - ErrorCode parse(const char* buf, int len, ::google::protobuf::Message* message); - void fillEmptyBuffer(muduo::net::Buffer* buf, const google::protobuf::Message& message); - - static int32_t checksum(const void* buf, int len); - static bool validateChecksum(const char* buf, int len); - static int32_t asInt32(const char* buf); - static void defaultErrorCallback(const TcpConnectionPtr&, - Buffer*, - Timestamp, - ErrorCode); - - private: - const ::google::protobuf::Message* prototype_; - const string tag_; - ProtobufMessageCallback messageCallback_; - RawMessageCallback rawCb_; - ErrorCallback errorCallback_; - const int kMinMessageLen; -}; - -template // TAG must be a variable with external linkage, not a string literal -class ProtobufCodecLiteT -{ - static_assert(std::is_base_of::value, "CODEC should be derived from ProtobufCodecLite"); - public: - typedef std::shared_ptr ConcreteMessagePtr; - typedef std::function ProtobufMessageCallback; - typedef ProtobufCodecLite::RawMessageCallback RawMessageCallback; - typedef ProtobufCodecLite::ErrorCallback ErrorCallback; - - explicit ProtobufCodecLiteT(const ProtobufMessageCallback& messageCb, - const RawMessageCallback& rawCb = RawMessageCallback(), - const ErrorCallback& errorCb = ProtobufCodecLite::defaultErrorCallback) - : messageCallback_(messageCb), - codec_(&MSG::default_instance(), - TAG, - std::bind(&ProtobufCodecLiteT::onRpcMessage, this, _1, _2, _3), - rawCb, - errorCb) - { - } - - const string& tag() const { return codec_.tag(); } - - void send(const TcpConnectionPtr& conn, - const MSG& message) - { - codec_.send(conn, message); - } - - void onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime) - { - codec_.onMessage(conn, buf, receiveTime); - } - - // internal - void onRpcMessage(const TcpConnectionPtr& conn, - const MessagePtr& message, - Timestamp receiveTime) - { - messageCallback_(conn, ::muduo::down_pointer_cast(message), receiveTime); - } - - void fillEmptyBuffer(muduo::net::Buffer* buf, const MSG& message) - { - codec_.fillEmptyBuffer(buf, message); - } - - private: - ProtobufMessageCallback messageCallback_; - CODEC codec_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H diff --git a/include/muduo/net/protorpc/CMakeLists.txt b/include/muduo/net/protorpc/CMakeLists.txt deleted file mode 100644 index 1e5f153..0000000 --- a/include/muduo/net/protorpc/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -add_custom_command(OUTPUT rpc.pb.cc rpc.pb.h - COMMAND protoc - ARGS --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/rpc.proto -I${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS rpc.proto - VERBATIM ) - -set_source_files_properties(rpc.pb.cc PROPERTIES COMPILE_FLAGS "-Wno-conversion") -include_directories(${PROJECT_BINARY_DIR}) - -add_library(muduo_protorpc_wire rpc.pb.cc RpcCodec.cc) -set_target_properties(muduo_protorpc_wire PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") - -#add_library(muduo_protorpc_wire_cpp11 rpc.pb.cc RpcCodec.cc) -#set_target_properties(muduo_protorpc_wire_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") - -if(MUDUO_BUILD_EXAMPLES) -add_executable(protobuf_rpc_wire_test RpcCodec_test.cc) -target_link_libraries(protobuf_rpc_wire_test muduo_protorpc_wire muduo_protobuf_codec) -set_target_properties(protobuf_rpc_wire_test PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") -endif() - -add_library(muduo_protorpc RpcChannel.cc RpcServer.cc) -set_target_properties(muduo_protorpc PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") -target_link_libraries(muduo_protorpc muduo_protorpc_wire muduo_protobuf_codec muduo_net protobuf z) - -if(TCMALLOC_LIBRARY) - target_link_libraries(muduo_protorpc tcmalloc_and_profiler) -endif() - -install(TARGETS muduo_protorpc_wire muduo_protorpc DESTINATION lib) -#install(TARGETS muduo_protorpc_wire_cpp11 DESTINATION lib) - -set(HEADERS - RpcCodec.h - RpcChannel.h - RpcServer.h - rpc.proto - rpcservice.proto - ${PROJECT_BINARY_DIR}/muduo/net/protorpc/rpc.pb.h - ) -install(FILES ${HEADERS} DESTINATION include/muduo/net/protorpc) - diff --git a/include/muduo/net/protorpc/README b/include/muduo/net/protorpc/README deleted file mode 100644 index 0db4c85..0000000 --- a/include/muduo/net/protorpc/README +++ /dev/null @@ -1,5 +0,0 @@ -This is an proof of concept implementation of Google Protobuf RPC using muduo. -The object lifetime management is for from ideal and doesn't follow the usual -muduo approach. - -Please consider using http://github.com/chenshuo/muduo-protorpc instead. diff --git a/include/muduo/net/protorpc/RpcChannel.cc b/include/muduo/net/protorpc/RpcChannel.cc deleted file mode 100644 index d18e081..0000000 --- a/include/muduo/net/protorpc/RpcChannel.cc +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/protorpc/RpcChannel.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/protorpc/rpc.pb.h" - -#include - -using namespace muduo; -using namespace muduo::net; - -RpcChannel::RpcChannel() - : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), - services_(NULL) -{ - LOG_INFO << "RpcChannel::ctor - " << this; -} - -RpcChannel::RpcChannel(const TcpConnectionPtr& conn) - : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), - conn_(conn), - services_(NULL) -{ - LOG_INFO << "RpcChannel::ctor - " << this; -} - -RpcChannel::~RpcChannel() -{ - LOG_INFO << "RpcChannel::dtor - " << this; - for (const auto& outstanding : outstandings_) - { - OutstandingCall out = outstanding.second; - delete out.response; - delete out.done; - } -} - - // Call the given method of the remote service. The signature of this - // procedure looks the same as Service::CallMethod(), but the requirements - // are less strict in one important way: the request and response objects - // need not be of any specific class as long as their descriptors are - // method->input_type() and method->output_type(). -void RpcChannel::CallMethod(const ::google::protobuf::MethodDescriptor* method, - google::protobuf::RpcController* controller, - const ::google::protobuf::Message* request, - ::google::protobuf::Message* response, - ::google::protobuf::Closure* done) -{ - RpcMessage message; - message.set_type(REQUEST); - int64_t id = id_.incrementAndGet(); - message.set_id(id); - message.set_service(method->service()->full_name()); - message.set_method(method->name()); - message.set_request(request->SerializeAsString()); // FIXME: error check - - OutstandingCall out = { response, done }; - { - MutexLockGuard lock(mutex_); - outstandings_[id] = out; - } - codec_.send(conn_, message); -} - -void RpcChannel::onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime) -{ - codec_.onMessage(conn, buf, receiveTime); -} - -void RpcChannel::onRpcMessage(const TcpConnectionPtr& conn, - const RpcMessagePtr& messagePtr, - Timestamp receiveTime) -{ - assert(conn == conn_); - //printf("%s\n", message.DebugString().c_str()); - RpcMessage& message = *messagePtr; - if (message.type() == RESPONSE) - { - int64_t id = message.id(); - assert(message.has_response() || message.has_error()); - - OutstandingCall out = { NULL, NULL }; - - { - MutexLockGuard lock(mutex_); - std::map::iterator it = outstandings_.find(id); - if (it != outstandings_.end()) - { - out = it->second; - outstandings_.erase(it); - } - } - - if (out.response) - { - std::unique_ptr d(out.response); - if (message.has_response()) - { - out.response->ParseFromString(message.response()); - } - if (out.done) - { - out.done->Run(); - } - } - } - else if (message.type() == REQUEST) - { - // FIXME: extract to a function - ErrorCode error = WRONG_PROTO; - if (services_) - { - std::map::const_iterator it = services_->find(message.service()); - if (it != services_->end()) - { - google::protobuf::Service* service = it->second; - assert(service != NULL); - const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); - const google::protobuf::MethodDescriptor* method - = desc->FindMethodByName(message.method()); - if (method) - { - std::unique_ptr request(service->GetRequestPrototype(method).New()); - if (request->ParseFromString(message.request())) - { - google::protobuf::Message* response = service->GetResponsePrototype(method).New(); - // response is deleted in doneCallback - int64_t id = message.id(); - service->CallMethod(method, NULL, get_pointer(request), response, - NewCallback(this, &RpcChannel::doneCallback, response, id)); - error = NO_ERROR; - } - else - { - error = INVALID_REQUEST; - } - } - else - { - error = NO_METHOD; - } - } - else - { - error = NO_SERVICE; - } - } - else - { - error = NO_SERVICE; - } - if (error != NO_ERROR) - { - RpcMessage response; - response.set_type(RESPONSE); - response.set_id(message.id()); - response.set_error(error); - codec_.send(conn_, response); - } - } - else if (message.type() == ERROR) - { - } -} - -void RpcChannel::doneCallback(::google::protobuf::Message* response, int64_t id) -{ - std::unique_ptr d(response); - RpcMessage message; - message.set_type(RESPONSE); - message.set_id(id); - message.set_response(response->SerializeAsString()); // FIXME: error check - codec_.send(conn_, message); -} - diff --git a/include/muduo/net/protorpc/RpcChannel.h b/include/muduo/net/protorpc/RpcChannel.h deleted file mode 100644 index 172b41e..0000000 --- a/include/muduo/net/protorpc/RpcChannel.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_PROTORPC_RPCCHANNEL_H -#define MUDUO_NET_PROTORPC_RPCCHANNEL_H - -#include "muduo/base/Atomic.h" -#include "muduo/base/Mutex.h" -#include "muduo/net/protorpc/RpcCodec.h" - -#include - -#include - -// Service and RpcChannel classes are incorporated from -// google/protobuf/service.h - -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -namespace google { -namespace protobuf { - -// Defined in other files. -class Descriptor; // descriptor.h -class ServiceDescriptor; // descriptor.h -class MethodDescriptor; // descriptor.h -class Message; // message.h - -class Closure; - -class RpcController; -class Service; - -} // namespace protobuf -} // namespace google - - -namespace muduo -{ -namespace net -{ - -// Abstract interface for an RPC channel. An RpcChannel represents a -// communication line to a Service which can be used to call that Service's -// methods. The Service may be running on another machine. Normally, you -// should not call an RpcChannel directly, but instead construct a stub Service -// wrapping it. Example: -// FIXME: update here -// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234"); -// MyService* service = new MyService::Stub(channel); -// service->MyMethod(request, &response, callback); -class RpcChannel : public ::google::protobuf::RpcChannel -{ - public: - RpcChannel(); - - explicit RpcChannel(const TcpConnectionPtr& conn); - - ~RpcChannel() override; - - void setConnection(const TcpConnectionPtr& conn) - { - conn_ = conn; - } - - void setServices(const std::map* services) - { - services_ = services; - } - - // Call the given method of the remote service. The signature of this - // procedure looks the same as Service::CallMethod(), but the requirements - // are less strict in one important way: the request and response objects - // need not be of any specific class as long as their descriptors are - // method->input_type() and method->output_type(). - void CallMethod(const ::google::protobuf::MethodDescriptor* method, - ::google::protobuf::RpcController* controller, - const ::google::protobuf::Message* request, - ::google::protobuf::Message* response, - ::google::protobuf::Closure* done) override; - - void onMessage(const TcpConnectionPtr& conn, - Buffer* buf, - Timestamp receiveTime); - - private: - void onRpcMessage(const TcpConnectionPtr& conn, - const RpcMessagePtr& messagePtr, - Timestamp receiveTime); - - void doneCallback(::google::protobuf::Message* response, int64_t id); - - struct OutstandingCall - { - ::google::protobuf::Message* response; - ::google::protobuf::Closure* done; - }; - - RpcCodec codec_; - TcpConnectionPtr conn_; - AtomicInt64 id_; - - MutexLock mutex_; - std::map outstandings_ GUARDED_BY(mutex_); - - const std::map* services_; -}; -typedef std::shared_ptr RpcChannelPtr; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_PROTORPC_RPCCHANNEL_H diff --git a/include/muduo/net/protorpc/RpcCodec.cc b/include/muduo/net/protorpc/RpcCodec.cc deleted file mode 100644 index e466e1d..0000000 --- a/include/muduo/net/protorpc/RpcCodec.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/protorpc/RpcCodec.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/Endian.h" -#include "muduo/net/TcpConnection.h" - -#include "muduo/net/protorpc/rpc.pb.h" -#include "muduo/net/protorpc/google-inl.h" - -using namespace muduo; -using namespace muduo::net; - -namespace -{ - int ProtobufVersionCheck() - { - GOOGLE_PROTOBUF_VERIFY_VERSION; - return 0; - } - int dummy __attribute__ ((unused)) = ProtobufVersionCheck(); -} - -namespace muduo -{ -namespace net -{ -const char rpctag [] = "RPC0"; -} -} diff --git a/include/muduo/net/protorpc/RpcCodec.h b/include/muduo/net/protorpc/RpcCodec.h deleted file mode 100644 index 07fab9c..0000000 --- a/include/muduo/net/protorpc/RpcCodec.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_PROTORPC_RPCCODEC_H -#define MUDUO_NET_PROTORPC_RPCCODEC_H - -#include "muduo/base/Timestamp.h" -#include "muduo/net/protobuf/ProtobufCodecLite.h" - -namespace muduo -{ -namespace net -{ - -class Buffer; -class TcpConnection; -typedef std::shared_ptr TcpConnectionPtr; - -class RpcMessage; -typedef std::shared_ptr RpcMessagePtr; -extern const char rpctag[];// = "RPC0"; - -// wire format -// -// Field Length Content -// -// size 4-byte N+8 -// "RPC0" 4-byte -// payload N-byte -// checksum 4-byte adler32 of "RPC0"+payload -// - -typedef ProtobufCodecLiteT RpcCodec; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_PROTORPC_RPCCODEC_H diff --git a/include/muduo/net/protorpc/RpcCodec_test.cc b/include/muduo/net/protorpc/RpcCodec_test.cc deleted file mode 100644 index 645fffd..0000000 --- a/include/muduo/net/protorpc/RpcCodec_test.cc +++ /dev/null @@ -1,81 +0,0 @@ -#undef NDEBUG -#include "muduo/net/protorpc/RpcCodec.h" -#include "muduo/net/protorpc/rpc.pb.h" -#include "muduo/net/protobuf/ProtobufCodecLite.h" -#include "muduo/net/Buffer.h" - -#include - -using namespace muduo; -using namespace muduo::net; - -void rpcMessageCallback(const TcpConnectionPtr&, - const RpcMessagePtr&, - Timestamp) -{ -} - -MessagePtr g_msgptr; -void messageCallback(const TcpConnectionPtr&, - const MessagePtr& msg, - Timestamp) -{ - g_msgptr = msg; -} - -void print(const Buffer& buf) -{ - printf("encoded to %zd bytes\n", buf.readableBytes()); - for (size_t i = 0; i < buf.readableBytes(); ++i) - { - unsigned char ch = static_cast(buf.peek()[i]); - - printf("%2zd: 0x%02x %c\n", i, ch, isgraph(ch) ? ch : ' '); - } -} - -char rpctag[] = "RPC0"; - -int main() -{ - RpcMessage message; - message.set_type(REQUEST); - message.set_id(2); - char wire[] = "\0\0\0\x13" "RPC0" "\x08\x01\x11\x02\0\0\0\0\0\0\0" "\x0f\xef\x01\x32"; - string expected(wire, sizeof(wire)-1); - string s1, s2; - Buffer buf1, buf2; - { - RpcCodec codec(rpcMessageCallback); - codec.fillEmptyBuffer(&buf1, message); - print(buf1); - s1 = buf1.toStringPiece().as_string(); - } - - { - ProtobufCodecLite codec(&RpcMessage::default_instance(), "RPC0", messageCallback); - codec.fillEmptyBuffer(&buf2, message); - print(buf2); - s2 = buf2.toStringPiece().as_string(); - codec.onMessage(TcpConnectionPtr(), &buf1, Timestamp::now()); - assert(g_msgptr); - assert(g_msgptr->DebugString() == message.DebugString()); - g_msgptr.reset(); - } - assert(s1 == s2); - assert(s1 == expected); - assert(s2 == expected); - - { - Buffer buf; - ProtobufCodecLite codec(&RpcMessage::default_instance(), "XYZ", messageCallback); - codec.fillEmptyBuffer(&buf, message); - print(buf); - s2 = buf.toStringPiece().as_string(); - codec.onMessage(TcpConnectionPtr(), &buf, Timestamp::now()); - assert(g_msgptr); - assert(g_msgptr->DebugString() == message.DebugString()); - } - - google::protobuf::ShutdownProtobufLibrary(); -} diff --git a/include/muduo/net/protorpc/RpcServer.cc b/include/muduo/net/protorpc/RpcServer.cc deleted file mode 100644 index fc1248b..0000000 --- a/include/muduo/net/protorpc/RpcServer.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) - -#include "muduo/net/protorpc/RpcServer.h" - -#include "muduo/base/Logging.h" -#include "muduo/net/protorpc/RpcChannel.h" - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -RpcServer::RpcServer(EventLoop* loop, - const InetAddress& listenAddr) - : server_(loop, listenAddr, "RpcServer") -{ - server_.setConnectionCallback( - std::bind(&RpcServer::onConnection, this, _1)); -// server_.setMessageCallback( -// std::bind(&RpcServer::onMessage, this, _1, _2, _3)); -} - -void RpcServer::registerService(google::protobuf::Service* service) -{ - const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); - services_[desc->full_name()] = service; -} - -void RpcServer::start() -{ - server_.start(); -} - -void RpcServer::onConnection(const TcpConnectionPtr& conn) -{ - LOG_INFO << "RpcServer - " << conn->peerAddress().toIpPort() << " -> " - << conn->localAddress().toIpPort() << " is " - << (conn->connected() ? "UP" : "DOWN"); - if (conn->connected()) - { - RpcChannelPtr channel(new RpcChannel(conn)); - channel->setServices(&services_); - conn->setMessageCallback( - std::bind(&RpcChannel::onMessage, get_pointer(channel), _1, _2, _3)); - conn->setContext(channel); - } - else - { - conn->setContext(RpcChannelPtr()); - // FIXME: - } -} - -// void RpcServer::onMessage(const TcpConnectionPtr& conn, -// Buffer* buf, -// Timestamp time) -// { -// RpcChannelPtr& channel = boost::any_cast(conn->getContext()); -// channel->onMessage(conn, buf, time); -// } - diff --git a/include/muduo/net/protorpc/RpcServer.h b/include/muduo/net/protorpc/RpcServer.h deleted file mode 100644 index 6818801..0000000 --- a/include/muduo/net/protorpc/RpcServer.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2010, Shuo Chen. All rights reserved. -// http://code.google.com/p/muduo/ -// -// Use of this source code is governed by a BSD-style license -// that can be found in the License file. - -// Author: Shuo Chen (chenshuo at chenshuo dot com) -// -// This is a public header file, it must only include public header files. - -#ifndef MUDUO_NET_PROTORPC_RPCSERVER_H -#define MUDUO_NET_PROTORPC_RPCSERVER_H - -#include "muduo/net/TcpServer.h" - -namespace google { -namespace protobuf { - -class Service; - -} // namespace protobuf -} // namespace google - -namespace muduo -{ -namespace net -{ - -class RpcServer -{ - public: - RpcServer(EventLoop* loop, - const InetAddress& listenAddr); - - void setThreadNum(int numThreads) - { - server_.setThreadNum(numThreads); - } - - void registerService(::google::protobuf::Service*); - void start(); - - private: - void onConnection(const TcpConnectionPtr& conn); - - // void onMessage(const TcpConnectionPtr& conn, - // Buffer* buf, - // Timestamp time); - - TcpServer server_; - std::map services_; -}; - -} // namespace net -} // namespace muduo - -#endif // MUDUO_NET_PROTORPC_RPCSERVER_H diff --git a/include/muduo/net/protorpc/google-inl.h b/include/muduo/net/protorpc/google-inl.h deleted file mode 100644 index 2a905a9..0000000 --- a/include/muduo/net/protorpc/google-inl.h +++ /dev/null @@ -1,84 +0,0 @@ -// ByteSizeConsistencyError and InitializationErrorMessage are -// copied from google/protobuf/message_lite.cc - -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Authors: wink@google.com (Wink Saville), -// kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include - -// When serializing, we first compute the byte size, then serialize the message. -// If serialization produces a different number of bytes than expected, we -// call this function, which crashes. The problem could be due to a bug in the -// protobuf implementation but is more likely caused by concurrent modification -// of the message. This function attempts to distinguish between the two and -// provide a useful error message. -inline -void ByteSizeConsistencyError(int byte_size_before_serialization, - int byte_size_after_serialization, - int bytes_produced_by_serialization) -{ - GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) - << "Protocol message was modified concurrently during serialization."; - GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) - << "Byte size calculation and serialization were inconsistent. This " - "may indicate a bug in protocol buffers or it may be caused by " - "concurrent modification of the message."; - GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; -} - -inline -std::string InitializationErrorMessage(const char* action, - const google::protobuf::MessageLite& message) -{ - // Note: We want to avoid depending on strutil in the lite library, otherwise - // we'd use: - // - // return strings::Substitute( - // "Can't $0 message of type \"$1\" because it is missing required " - // "fields: $2", - // action, message.GetTypeName(), - // message.InitializationErrorString()); - - std::string result; - result += "Can't "; - result += action; - result += " message of type \""; - result += message.GetTypeName(); - result += "\" because it is missing required fields: "; - result += message.InitializationErrorString(); - return result; -} - - diff --git a/include/muduo/net/protorpc/rpc.proto b/include/muduo/net/protorpc/rpc.proto deleted file mode 100644 index 941e235..0000000 --- a/include/muduo/net/protorpc/rpc.proto +++ /dev/null @@ -1,36 +0,0 @@ -package muduo.net; -// option go_package = "muduorpc"; -option java_package = "com.chenshuo.muduo.protorpc"; -option java_outer_classname = "RpcProto"; - -enum MessageType -{ - REQUEST = 1; - RESPONSE = 2; - ERROR = 3; // not used -} - -enum ErrorCode -{ - NO_ERROR = 0; - WRONG_PROTO = 1; - NO_SERVICE = 2; - NO_METHOD = 3; - INVALID_REQUEST = 4; - INVALID_RESPONSE = 5; - TIMEOUT = 6; -} - -message RpcMessage -{ - required MessageType type = 1; - required fixed64 id = 2; - - optional string service = 3; - optional string method = 4; - optional bytes request = 5; - - optional bytes response = 6; - - optional ErrorCode error = 7; -} diff --git a/include/muduo/net/protorpc/rpcservice.proto b/include/muduo/net/protorpc/rpcservice.proto deleted file mode 100644 index f973234..0000000 --- a/include/muduo/net/protorpc/rpcservice.proto +++ /dev/null @@ -1,44 +0,0 @@ -package muduo.net; - -option cc_generic_services = true; -option java_generic_services = true; -option py_generic_services = true; - -option java_package = "com.chenshuo.muduo.protorpc"; -option java_outer_classname = "RpcServiceProto"; - -//import "google/protobuf/descriptor.proto"; -import "rpc.proto"; - -message ListRpcRequest -{ - optional string service_name = 1; - optional bool list_method = 2; -} - -message ListRpcResponse -{ - required ErrorCode error = 1; - repeated string service_name = 2; - repeated string method_name = 3; -} - -message GetServiceRequest -{ - required string service_name = 1; -} - -message GetServiceResponse -{ - required ErrorCode error = 1; - repeated string proto_file = 2; - repeated string proto_file_name = 3; -} - -// the meta service -service RpcService -{ - rpc listRpc (ListRpcRequest) returns (ListRpcResponse); - rpc getService (GetServiceRequest) returns (GetServiceResponse); -} - diff --git a/include/muduo/net/tests/Buffer_unittest.cc b/include/muduo/net/tests/Buffer_unittest.cc deleted file mode 100644 index af7fb81..0000000 --- a/include/muduo/net/tests/Buffer_unittest.cc +++ /dev/null @@ -1,170 +0,0 @@ -#include "muduo/net/Buffer.h" - -//#define BOOST_TEST_MODULE BufferTest -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include - -using muduo::string; -using muduo::net::Buffer; - -BOOST_AUTO_TEST_CASE(testBufferAppendRetrieve) -{ - Buffer buf; - BOOST_CHECK_EQUAL(buf.readableBytes(), 0); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); - - const string str(200, 'x'); - buf.append(str); - BOOST_CHECK_EQUAL(buf.readableBytes(), str.size()); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); - - const string str2 = buf.retrieveAsString(50); - BOOST_CHECK_EQUAL(str2.size(), 50); - BOOST_CHECK_EQUAL(buf.readableBytes(), str.size() - str2.size()); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); - BOOST_CHECK_EQUAL(str2, string(50, 'x')); - - buf.append(str); - BOOST_CHECK_EQUAL(buf.readableBytes(), 2*str.size() - str2.size()); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - 2*str.size()); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); - - const string str3 = buf.retrieveAllAsString(); - BOOST_CHECK_EQUAL(str3.size(), 350); - BOOST_CHECK_EQUAL(buf.readableBytes(), 0); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); - BOOST_CHECK_EQUAL(str3, string(350, 'x')); -} - -BOOST_AUTO_TEST_CASE(testBufferGrow) -{ - Buffer buf; - buf.append(string(400, 'y')); - BOOST_CHECK_EQUAL(buf.readableBytes(), 400); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); - - buf.retrieve(50); - BOOST_CHECK_EQUAL(buf.readableBytes(), 350); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); - - buf.append(string(1000, 'z')); - BOOST_CHECK_EQUAL(buf.readableBytes(), 1350); - BOOST_CHECK_EQUAL(buf.writableBytes(), 0); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); // FIXME - - buf.retrieveAll(); - BOOST_CHECK_EQUAL(buf.readableBytes(), 0); - BOOST_CHECK_EQUAL(buf.writableBytes(), 1400); // FIXME - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); -} - -BOOST_AUTO_TEST_CASE(testBufferInsideGrow) -{ - Buffer buf; - buf.append(string(800, 'y')); - BOOST_CHECK_EQUAL(buf.readableBytes(), 800); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); - - buf.retrieve(500); - BOOST_CHECK_EQUAL(buf.readableBytes(), 300); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+500); - - buf.append(string(300, 'z')); - BOOST_CHECK_EQUAL(buf.readableBytes(), 600); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-600); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); -} - -BOOST_AUTO_TEST_CASE(testBufferShrink) -{ - Buffer buf; - buf.append(string(2000, 'y')); - BOOST_CHECK_EQUAL(buf.readableBytes(), 2000); - BOOST_CHECK_EQUAL(buf.writableBytes(), 0); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); - - buf.retrieve(1500); - BOOST_CHECK_EQUAL(buf.readableBytes(), 500); - BOOST_CHECK_EQUAL(buf.writableBytes(), 0); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+1500); - - buf.shrink(0); - BOOST_CHECK_EQUAL(buf.readableBytes(), 500); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-500); - BOOST_CHECK_EQUAL(buf.retrieveAllAsString(), string(500, 'y')); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); -} - -BOOST_AUTO_TEST_CASE(testBufferPrepend) -{ - Buffer buf; - buf.append(string(200, 'y')); - BOOST_CHECK_EQUAL(buf.readableBytes(), 200); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); - - int x = 0; - buf.prepend(&x, sizeof x); - BOOST_CHECK_EQUAL(buf.readableBytes(), 204); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); - BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend - 4); -} - -BOOST_AUTO_TEST_CASE(testBufferReadInt) -{ - Buffer buf; - buf.append("HTTP"); - - BOOST_CHECK_EQUAL(buf.readableBytes(), 4); - BOOST_CHECK_EQUAL(buf.peekInt8(), 'H'); - int top16 = buf.peekInt16(); - BOOST_CHECK_EQUAL(top16, 'H'*256 + 'T'); - BOOST_CHECK_EQUAL(buf.peekInt32(), top16*65536 + 'T'*256 + 'P'); - - BOOST_CHECK_EQUAL(buf.readInt8(), 'H'); - BOOST_CHECK_EQUAL(buf.readInt16(), 'T'*256 + 'T'); - BOOST_CHECK_EQUAL(buf.readInt8(), 'P'); - BOOST_CHECK_EQUAL(buf.readableBytes(), 0); - BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); - - buf.appendInt8(-1); - buf.appendInt16(-2); - buf.appendInt32(-3); - BOOST_CHECK_EQUAL(buf.readableBytes(), 7); - BOOST_CHECK_EQUAL(buf.readInt8(), -1); - BOOST_CHECK_EQUAL(buf.readInt16(), -2); - BOOST_CHECK_EQUAL(buf.readInt32(), -3); -} - -BOOST_AUTO_TEST_CASE(testBufferFindEOL) -{ - Buffer buf; - buf.append(string(100000, 'x')); - const char* null = NULL; - BOOST_CHECK_EQUAL(buf.findEOL(), null); - BOOST_CHECK_EQUAL(buf.findEOL(buf.peek()+90000), null); -} - -void output(Buffer&& buf, const void* inner) -{ - Buffer newbuf(std::move(buf)); - // printf("New Buffer at %p, inner %p\n", &newbuf, newbuf.peek()); - BOOST_CHECK_EQUAL(inner, newbuf.peek()); -} - -// NOTE: This test fails in g++ 4.4, passes in g++ 4.6. -BOOST_AUTO_TEST_CASE(testMove) -{ - Buffer buf; - buf.append("muduo", 5); - const void* inner = buf.peek(); - // printf("Buffer at %p, inner %p\n", &buf, inner); - output(std::move(buf), inner); -} diff --git a/include/muduo/net/tests/CMakeLists.txt b/include/muduo/net/tests/CMakeLists.txt deleted file mode 100644 index a7aa3a0..0000000 --- a/include/muduo/net/tests/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -add_executable(channel_test Channel_test.cc) -target_link_libraries(channel_test muduo_net) - -add_executable(echoserver_unittest EchoServer_unittest.cc) -target_link_libraries(echoserver_unittest muduo_net) - -add_executable(echoclient_unittest EchoClient_unittest.cc) -target_link_libraries(echoclient_unittest muduo_net) - -add_executable(eventloop_unittest EventLoop_unittest.cc) -target_link_libraries(eventloop_unittest muduo_net) - -add_executable(eventloopthread_unittest EventLoopThread_unittest.cc) -target_link_libraries(eventloopthread_unittest muduo_net) - -add_executable(eventloopthreadpool_unittest EventLoopThreadPool_unittest.cc) -target_link_libraries(eventloopthreadpool_unittest muduo_net) - -if(BOOSTTEST_LIBRARY) -add_executable(buffer_unittest Buffer_unittest.cc) -target_link_libraries(buffer_unittest muduo_net boost_unit_test_framework) -add_test(NAME buffer_unittest COMMAND buffer_unittest) - -add_executable(inetaddress_unittest InetAddress_unittest.cc) -target_link_libraries(inetaddress_unittest muduo_net boost_unit_test_framework) -add_test(NAME inetaddress_unittest COMMAND inetaddress_unittest) - -if(ZLIB_FOUND) - add_executable(zlibstream_unittest ZlibStream_unittest.cc) - target_link_libraries(zlibstream_unittest muduo_net boost_unit_test_framework z) - # set_target_properties(zlibstream_unittest PROPERTIES COMPILE_FLAGS "-std=c++0x") -endif() - -endif() - -add_executable(tcpclient_reg1 TcpClient_reg1.cc) -target_link_libraries(tcpclient_reg1 muduo_net) - -add_executable(tcpclient_reg2 TcpClient_reg2.cc) -target_link_libraries(tcpclient_reg2 muduo_net) - -add_executable(tcpclient_reg3 TcpClient_reg3.cc) -target_link_libraries(tcpclient_reg3 muduo_net) - -add_executable(timerqueue_unittest TimerQueue_unittest.cc) -target_link_libraries(timerqueue_unittest muduo_net) -add_test(NAME timerqueue_unittest COMMAND timerqueue_unittest) - diff --git a/include/muduo/net/tests/Channel_test.cc b/include/muduo/net/tests/Channel_test.cc deleted file mode 100644 index 6276531..0000000 --- a/include/muduo/net/tests/Channel_test.cc +++ /dev/null @@ -1,112 +0,0 @@ -#include "muduo/base/Logging.h" -#include "muduo/net/Channel.h" -#include "muduo/net/EventLoop.h" - -#include -#include - -#include -#include -#include - -using namespace muduo; -using namespace muduo::net; - -void print(const char* msg) -{ - static std::map lasts; - Timestamp& last = lasts[msg]; - Timestamp now = Timestamp::now(); - printf("%s tid %d %s delay %f\n", now.toString().c_str(), CurrentThread::tid(), - msg, timeDifference(now, last)); - last = now; -} - -namespace muduo -{ -namespace net -{ -namespace detail -{ -int createTimerfd(); -void readTimerfd(int timerfd, Timestamp now); -} -} -} - -// Use relative time, immunized to wall clock changes. -class PeriodicTimer -{ - public: - PeriodicTimer(EventLoop* loop, double interval, const TimerCallback& cb) - : loop_(loop), - timerfd_(muduo::net::detail::createTimerfd()), - timerfdChannel_(loop, timerfd_), - interval_(interval), - cb_(cb) - { - timerfdChannel_.setReadCallback( - std::bind(&PeriodicTimer::handleRead, this)); - timerfdChannel_.enableReading(); - } - - void start() - { - struct itimerspec spec; - memZero(&spec, sizeof spec); - spec.it_interval = toTimeSpec(interval_); - spec.it_value = spec.it_interval; - int ret = ::timerfd_settime(timerfd_, 0 /* relative timer */, &spec, NULL); - if (ret) - { - LOG_SYSERR << "timerfd_settime()"; - } - } - - ~PeriodicTimer() - { - timerfdChannel_.disableAll(); - timerfdChannel_.remove(); - ::close(timerfd_); - } - - private: - void handleRead() - { - loop_->assertInLoopThread(); - muduo::net::detail::readTimerfd(timerfd_, Timestamp::now()); - if (cb_) - cb_(); - } - - static struct timespec toTimeSpec(double seconds) - { - struct timespec ts; - memZero(&ts, sizeof ts); - const int64_t kNanoSecondsPerSecond = 1000000000; - const int kMinInterval = 100000; - int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); - if (nanoseconds < kMinInterval) - nanoseconds = kMinInterval; - ts.tv_sec = static_cast(nanoseconds / kNanoSecondsPerSecond); - ts.tv_nsec = static_cast(nanoseconds % kNanoSecondsPerSecond); - return ts; - } - - EventLoop* loop_; - const int timerfd_; - Channel timerfdChannel_; - const double interval_; // in seconds - TimerCallback cb_; -}; - -int main(int argc, char* argv[]) -{ - LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid() - << " Try adjusting the wall clock, see what happens."; - EventLoop loop; - PeriodicTimer timer(&loop, 1, std::bind(print, "PeriodicTimer")); - timer.start(); - loop.runEvery(1, std::bind(print, "EventLoop::runEvery")); - loop.loop(); -} diff --git a/include/muduo/net/tests/EchoClient_unittest.cc b/include/muduo/net/tests/EchoClient_unittest.cc deleted file mode 100644 index 44d973a..0000000 --- a/include/muduo/net/tests/EchoClient_unittest.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include "muduo/net/TcpClient.h" - -#include "muduo/base/Logging.h" -#include "muduo/base/Thread.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/InetAddress.h" - -#include - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -int numThreads = 0; -class EchoClient; -std::vector> clients; -int current = 0; - -class EchoClient : noncopyable -{ - public: - EchoClient(EventLoop* loop, const InetAddress& listenAddr, const string& id) - : loop_(loop), - client_(loop, listenAddr, "EchoClient"+id) - { - client_.setConnectionCallback( - std::bind(&EchoClient::onConnection, this, _1)); - client_.setMessageCallback( - std::bind(&EchoClient::onMessage, this, _1, _2, _3)); - //client_.enableRetry(); - } - - void connect() - { - client_.connect(); - } - // void stop(); - - private: - void onConnection(const TcpConnectionPtr& conn) - { - LOG_TRACE << conn->localAddress().toIpPort() << " -> " - << conn->peerAddress().toIpPort() << " is " - << (conn->connected() ? "UP" : "DOWN"); - - if (conn->connected()) - { - ++current; - if (implicit_cast(current) < clients.size()) - { - clients[current]->connect(); - } - LOG_INFO << "*** connected " << current; - } - conn->send("world\n"); - } - - void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) - { - string msg(buf->retrieveAllAsString()); - LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); - if (msg == "quit\n") - { - conn->send("bye\n"); - conn->shutdown(); - } - else if (msg == "shutdown\n") - { - loop_->quit(); - } - else - { - conn->send(msg); - } - } - - EventLoop* loop_; - TcpClient client_; -}; - -int main(int argc, char* argv[]) -{ - LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); - if (argc > 1) - { - EventLoop loop; - bool ipv6 = argc > 3; - InetAddress serverAddr(argv[1], 2000, ipv6); - - int n = 1; - if (argc > 2) - { - n = atoi(argv[2]); - } - - clients.reserve(n); - for (int i = 0; i < n; ++i) - { - char buf[32]; - snprintf(buf, sizeof buf, "%d", i+1); - clients.emplace_back(new EchoClient(&loop, serverAddr, buf)); - } - - clients[current]->connect(); - loop.loop(); - } - else - { - printf("Usage: %s host_ip [current#]\n", argv[0]); - } -} - diff --git a/include/muduo/net/tests/EchoServer_unittest.cc b/include/muduo/net/tests/EchoServer_unittest.cc deleted file mode 100644 index 0875668..0000000 --- a/include/muduo/net/tests/EchoServer_unittest.cc +++ /dev/null @@ -1,86 +0,0 @@ -#include "muduo/net/TcpServer.h" - -#include "muduo/base/Logging.h" -#include "muduo/base/Thread.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/InetAddress.h" - -#include - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -int numThreads = 0; - -class EchoServer -{ - public: - EchoServer(EventLoop* loop, const InetAddress& listenAddr) - : loop_(loop), - server_(loop, listenAddr, "EchoServer") - { - server_.setConnectionCallback( - std::bind(&EchoServer::onConnection, this, _1)); - server_.setMessageCallback( - std::bind(&EchoServer::onMessage, this, _1, _2, _3)); - server_.setThreadNum(numThreads); - } - - void start() - { - server_.start(); - } - // void stop(); - - private: - void onConnection(const TcpConnectionPtr& conn) - { - LOG_TRACE << conn->peerAddress().toIpPort() << " -> " - << conn->localAddress().toIpPort() << " is " - << (conn->connected() ? "UP" : "DOWN"); - LOG_INFO << conn->getTcpInfoString(); - - conn->send("hello\n"); - } - - void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) - { - string msg(buf->retrieveAllAsString()); - LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); - if (msg == "exit\n") - { - conn->send("bye\n"); - conn->shutdown(); - } - if (msg == "quit\n") - { - loop_->quit(); - } - conn->send(msg); - } - - EventLoop* loop_; - TcpServer server_; -}; - -int main(int argc, char* argv[]) -{ - LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); - LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); - if (argc > 1) - { - numThreads = atoi(argv[1]); - } - bool ipv6 = argc > 2; - EventLoop loop; - InetAddress listenAddr(2000, false, ipv6); - EchoServer server(&loop, listenAddr); - - server.start(); - - loop.loop(); -} - diff --git a/include/muduo/net/tests/EventLoopThreadPool_unittest.cc b/include/muduo/net/tests/EventLoopThreadPool_unittest.cc deleted file mode 100644 index 1bf1bd3..0000000 --- a/include/muduo/net/tests/EventLoopThreadPool_unittest.cc +++ /dev/null @@ -1,68 +0,0 @@ -#include "muduo/net/EventLoopThreadPool.h" -#include "muduo/net/EventLoop.h" -#include "muduo/base/Thread.h" - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -void print(EventLoop* p = NULL) -{ - printf("main(): pid = %d, tid = %d, loop = %p\n", - getpid(), CurrentThread::tid(), p); -} - -void init(EventLoop* p) -{ - printf("init(): pid = %d, tid = %d, loop = %p\n", - getpid(), CurrentThread::tid(), p); -} - -int main() -{ - print(); - - EventLoop loop; - loop.runAfter(11, std::bind(&EventLoop::quit, &loop)); - - { - printf("Single thread %p:\n", &loop); - EventLoopThreadPool model(&loop, "single"); - model.setThreadNum(0); - model.start(init); - assert(model.getNextLoop() == &loop); - assert(model.getNextLoop() == &loop); - assert(model.getNextLoop() == &loop); - } - - { - printf("Another thread:\n"); - EventLoopThreadPool model(&loop, "another"); - model.setThreadNum(1); - model.start(init); - EventLoop* nextLoop = model.getNextLoop(); - nextLoop->runAfter(2, std::bind(print, nextLoop)); - assert(nextLoop != &loop); - assert(nextLoop == model.getNextLoop()); - assert(nextLoop == model.getNextLoop()); - ::sleep(3); - } - - { - printf("Three threads:\n"); - EventLoopThreadPool model(&loop, "three"); - model.setThreadNum(3); - model.start(init); - EventLoop* nextLoop = model.getNextLoop(); - nextLoop->runInLoop(std::bind(print, nextLoop)); - assert(nextLoop != &loop); - assert(nextLoop != model.getNextLoop()); - assert(nextLoop != model.getNextLoop()); - assert(nextLoop == model.getNextLoop()); - } - - loop.loop(); -} - diff --git a/include/muduo/net/tests/EventLoopThread_unittest.cc b/include/muduo/net/tests/EventLoopThread_unittest.cc deleted file mode 100644 index d67c128..0000000 --- a/include/muduo/net/tests/EventLoopThread_unittest.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "muduo/net/EventLoopThread.h" -#include "muduo/net/EventLoop.h" -#include "muduo/base/Thread.h" -#include "muduo/base/CountDownLatch.h" - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -void print(EventLoop* p = NULL) -{ - printf("print: pid = %d, tid = %d, loop = %p\n", - getpid(), CurrentThread::tid(), p); -} - -void quit(EventLoop* p) -{ - print(p); - p->quit(); -} - -int main() -{ - print(); - - { - EventLoopThread thr1; // never start - } - - { - // dtor calls quit() - EventLoopThread thr2; - EventLoop* loop = thr2.startLoop(); - loop->runInLoop(std::bind(print, loop)); - CurrentThread::sleepUsec(500 * 1000); - } - - { - // quit() before dtor - EventLoopThread thr3; - EventLoop* loop = thr3.startLoop(); - loop->runInLoop(std::bind(quit, loop)); - CurrentThread::sleepUsec(500 * 1000); - } -} - diff --git a/include/muduo/net/tests/EventLoop_unittest.cc b/include/muduo/net/tests/EventLoop_unittest.cc deleted file mode 100644 index 6cb6d7d..0000000 --- a/include/muduo/net/tests/EventLoop_unittest.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include "muduo/net/EventLoop.h" -#include "muduo/base/Thread.h" - -#include -#include -#include - -using namespace muduo; -using namespace muduo::net; - -EventLoop* g_loop; - -void callback() -{ - printf("callback(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); - EventLoop anotherLoop; -} - -void threadFunc() -{ - printf("threadFunc(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); - - assert(EventLoop::getEventLoopOfCurrentThread() == NULL); - EventLoop loop; - assert(EventLoop::getEventLoopOfCurrentThread() == &loop); - loop.runAfter(1.0, callback); - loop.loop(); -} - -int main() -{ - printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); - - assert(EventLoop::getEventLoopOfCurrentThread() == NULL); - EventLoop loop; - assert(EventLoop::getEventLoopOfCurrentThread() == &loop); - - Thread thread(threadFunc); - thread.start(); - - loop.loop(); -} diff --git a/include/muduo/net/tests/InetAddress_unittest.cc b/include/muduo/net/tests/InetAddress_unittest.cc deleted file mode 100644 index bdd31e0..0000000 --- a/include/muduo/net/tests/InetAddress_unittest.cc +++ /dev/null @@ -1,70 +0,0 @@ -#include "muduo/net/InetAddress.h" - -#include "muduo/base/Logging.h" - -//#define BOOST_TEST_MODULE InetAddressTest -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include - -using muduo::string; -using muduo::net::InetAddress; - -BOOST_AUTO_TEST_CASE(testInetAddress) -{ - InetAddress addr0(1234); - BOOST_CHECK_EQUAL(addr0.toIp(), string("0.0.0.0")); - BOOST_CHECK_EQUAL(addr0.toIpPort(), string("0.0.0.0:1234")); - BOOST_CHECK_EQUAL(addr0.port(), 1234); - - InetAddress addr1(4321, true); - BOOST_CHECK_EQUAL(addr1.toIp(), string("127.0.0.1")); - BOOST_CHECK_EQUAL(addr1.toIpPort(), string("127.0.0.1:4321")); - BOOST_CHECK_EQUAL(addr1.port(), 4321); - - InetAddress addr2("1.2.3.4", 8888); - BOOST_CHECK_EQUAL(addr2.toIp(), string("1.2.3.4")); - BOOST_CHECK_EQUAL(addr2.toIpPort(), string("1.2.3.4:8888")); - BOOST_CHECK_EQUAL(addr2.port(), 8888); - - InetAddress addr3("255.254.253.252", 65535); - BOOST_CHECK_EQUAL(addr3.toIp(), string("255.254.253.252")); - BOOST_CHECK_EQUAL(addr3.toIpPort(), string("255.254.253.252:65535")); - BOOST_CHECK_EQUAL(addr3.port(), 65535); -} - -BOOST_AUTO_TEST_CASE(testInet6Address) -{ - InetAddress addr0(1234, false, true); - BOOST_CHECK_EQUAL(addr0.toIp(), string("::")); - BOOST_CHECK_EQUAL(addr0.toIpPort(), string("[::]:1234")); - BOOST_CHECK_EQUAL(addr0.port(), 1234); - - InetAddress addr1(1234, true, true); - BOOST_CHECK_EQUAL(addr1.toIp(), string("::1")); - BOOST_CHECK_EQUAL(addr1.toIpPort(), string("[::1]:1234")); - BOOST_CHECK_EQUAL(addr1.port(), 1234); - - InetAddress addr2("2001:db8::1", 8888, true); - BOOST_CHECK_EQUAL(addr2.toIp(), string("2001:db8::1")); - BOOST_CHECK_EQUAL(addr2.toIpPort(), string("[2001:db8::1]:8888")); - BOOST_CHECK_EQUAL(addr2.port(), 8888); - - InetAddress addr3("fe80::1234:abcd:1", 8888); - BOOST_CHECK_EQUAL(addr3.toIp(), string("fe80::1234:abcd:1")); - BOOST_CHECK_EQUAL(addr3.toIpPort(), string("[fe80::1234:abcd:1]:8888")); - BOOST_CHECK_EQUAL(addr3.port(), 8888); -} - -BOOST_AUTO_TEST_CASE(testInetAddressResolve) -{ - InetAddress addr(80); - if (InetAddress::resolve("google.com", &addr)) - { - LOG_INFO << "google.com resolved to " << addr.toIpPort(); - } - else - { - LOG_ERROR << "Unable to resolve google.com"; - } -} diff --git a/include/muduo/net/tests/TcpClient_reg1.cc b/include/muduo/net/tests/TcpClient_reg1.cc deleted file mode 100644 index 41b76b2..0000000 --- a/include/muduo/net/tests/TcpClient_reg1.cc +++ /dev/null @@ -1,29 +0,0 @@ -// TcpClient::stop() called in the same iteration of IO event - -#include "muduo/base/Logging.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/TcpClient.h" - -using namespace muduo; -using namespace muduo::net; - -TcpClient* g_client; - -void timeout() -{ - LOG_INFO << "timeout"; - g_client->stop(); -} - -int main(int argc, char* argv[]) -{ - EventLoop loop; - InetAddress serverAddr("127.0.0.1", 2); // no such server - TcpClient client(&loop, serverAddr, "TcpClient"); - g_client = &client; - loop.runAfter(0.0, timeout); - loop.runAfter(1.0, std::bind(&EventLoop::quit, &loop)); - client.connect(); - CurrentThread::sleepUsec(100 * 1000); - loop.loop(); -} diff --git a/include/muduo/net/tests/TcpClient_reg2.cc b/include/muduo/net/tests/TcpClient_reg2.cc deleted file mode 100644 index 1637dbd..0000000 --- a/include/muduo/net/tests/TcpClient_reg2.cc +++ /dev/null @@ -1,30 +0,0 @@ -// TcpClient destructs when TcpConnection is connected but unique. - -#include "muduo/base/Logging.h" -#include "muduo/base/Thread.h" -#include "muduo/net/EventLoop.h" -#include "muduo/net/TcpClient.h" - -using namespace muduo; -using namespace muduo::net; - -void threadFunc(EventLoop* loop) -{ - InetAddress serverAddr("127.0.0.1", 1234); // should succeed - TcpClient client(loop, serverAddr, "TcpClient"); - client.connect(); - - CurrentThread::sleepUsec(1000*1000); - // client destructs when connected. -} - -int main(int argc, char* argv[]) -{ - Logger::setLogLevel(Logger::DEBUG); - - EventLoop loop; - loop.runAfter(3.0, std::bind(&EventLoop::quit, &loop)); - Thread thr(std::bind(threadFunc, &loop)); - thr.start(); - loop.loop(); -} diff --git a/include/muduo/net/tests/TcpClient_reg3.cc b/include/muduo/net/tests/TcpClient_reg3.cc deleted file mode 100644 index bb1e5ee..0000000 --- a/include/muduo/net/tests/TcpClient_reg3.cc +++ /dev/null @@ -1,24 +0,0 @@ -// TcpClient destructs in a different thread. - -#include "muduo/base/Logging.h" -#include "muduo/net/EventLoopThread.h" -#include "muduo/net/TcpClient.h" - -using namespace muduo; -using namespace muduo::net; - -int main(int argc, char* argv[]) -{ - Logger::setLogLevel(Logger::DEBUG); - - EventLoopThread loopThread; - { - InetAddress serverAddr("127.0.0.1", 1234); // should succeed - TcpClient client(loopThread.startLoop(), serverAddr, "TcpClient"); - client.connect(); - CurrentThread::sleepUsec(500 * 1000); // wait for connect - client.disconnect(); - } - - CurrentThread::sleepUsec(1000 * 1000); -} diff --git a/include/muduo/net/tests/TimerQueue_unittest.cc b/include/muduo/net/tests/TimerQueue_unittest.cc deleted file mode 100644 index 65cff93..0000000 --- a/include/muduo/net/tests/TimerQueue_unittest.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include "muduo/net/EventLoop.h" -#include "muduo/net/EventLoopThread.h" -#include "muduo/base/Thread.h" - -#include -#include - -using namespace muduo; -using namespace muduo::net; - -int cnt = 0; -EventLoop* g_loop; - -void printTid() -{ - printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); - printf("now %s\n", Timestamp::now().toString().c_str()); -} - -void print(const char* msg) -{ - printf("msg %s %s\n", Timestamp::now().toString().c_str(), msg); - if (++cnt == 20) - { - g_loop->quit(); - } -} - -void cancel(TimerId timer) -{ - g_loop->cancel(timer); - printf("cancelled at %s\n", Timestamp::now().toString().c_str()); -} - -int main() -{ - printTid(); - sleep(1); - { - EventLoop loop; - g_loop = &loop; - - print("main"); - loop.runAfter(1, std::bind(print, "once1")); - loop.runAfter(1.5, std::bind(print, "once1.5")); - loop.runAfter(2.5, std::bind(print, "once2.5")); - loop.runAfter(3.5, std::bind(print, "once3.5")); - TimerId t45 = loop.runAfter(4.5, std::bind(print, "once4.5")); - loop.runAfter(4.2, std::bind(cancel, t45)); - loop.runAfter(4.8, std::bind(cancel, t45)); - loop.runEvery(2, std::bind(print, "every2")); - TimerId t3 = loop.runEvery(3, std::bind(print, "every3")); - loop.runAfter(9.001, std::bind(cancel, t3)); - - loop.loop(); - print("main loop exits"); - } - sleep(1); - { - EventLoopThread loopThread; - EventLoop* loop = loopThread.startLoop(); - loop->runAfter(2, printTid); - sleep(3); - print("thread loop exits"); - } -} diff --git a/include/muduo/net/tests/ZlibStream_unittest.cc b/include/muduo/net/tests/ZlibStream_unittest.cc deleted file mode 100644 index 144dda0..0000000 --- a/include/muduo/net/tests/ZlibStream_unittest.cc +++ /dev/null @@ -1,91 +0,0 @@ -#include "muduo/net/ZlibStream.h" - -#include "muduo/base/Logging.h" - -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include - -#include - -BOOST_AUTO_TEST_CASE(testZlibOutputStream) -{ - muduo::net::Buffer output; - { - muduo::net::ZlibOutputStream stream(&output); - BOOST_CHECK_EQUAL(output.readableBytes(), 0); - } - BOOST_CHECK_EQUAL(output.readableBytes(), 8); -} - -BOOST_AUTO_TEST_CASE(testZlibOutputStream1) -{ - muduo::net::Buffer output; - muduo::net::ZlibOutputStream stream(&output); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); - stream.finish(); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); -} - -BOOST_AUTO_TEST_CASE(testZlibOutputStream2) -{ - muduo::net::Buffer output; - muduo::net::ZlibOutputStream stream(&output); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); - BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); - stream.finish(); - // printf("%zd\n", output.readableBytes()); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); -} - -BOOST_AUTO_TEST_CASE(testZlibOutputStream3) -{ - muduo::net::Buffer output; - muduo::net::ZlibOutputStream stream(&output); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); - for (int i = 0; i < 1024*1024; ++i) - { - BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); - } - stream.finish(); - // printf("total %zd\n", output.readableBytes()); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); -} - -BOOST_AUTO_TEST_CASE(testZlibOutputStream4) -{ - muduo::net::Buffer output; - muduo::net::ZlibOutputStream stream(&output); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); - muduo::string input; - for (int i = 0; i < 32768; ++i) - { - input += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-"[rand() % 64]; - } - - for (int i = 0; i < 10; ++i) - { - BOOST_CHECK(stream.write(input)); - } - stream.finish(); - // printf("total %zd\n", output.readableBytes()); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); -} - -BOOST_AUTO_TEST_CASE(testZlibOutputStream5) -{ - muduo::net::Buffer output; - muduo::net::ZlibOutputStream stream(&output); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); - muduo::string input(1024*1024, '_'); - for (int i = 0; i < 64; ++i) - { - BOOST_CHECK(stream.write(input)); - } - printf("bufsiz %d\n", stream.internalOutputBufferSize()); - LOG_INFO << "total_in " << stream.inputBytes(); - LOG_INFO << "total_out " << stream.outputBytes(); - stream.finish(); - printf("total %zd\n", output.readableBytes()); - BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); -} diff --git a/step.md b/step.md new file mode 100644 index 0000000..7a1c48d --- /dev/null +++ b/step.md @@ -0,0 +1,102 @@ +* 切换为root + +sudo -s +(**you passwd**) + +* 基本工具 +apt update +apt upgrade +apt install g++ +apt install cmake +apt install make +apt install git + +* 准备环境 +cd home +mkdir server +cd server + +* 准备第三方库 + + #下载boost库 +tar -jxvpf boost_1_74_0.tar.bz2 +cd boost_1_74_0 +./bootstrap.sh --with-libraries=all --with-toolset=gcc +./b2 install + + +cd /home/server +# muduo库 + +git clone https://github.com/chenshuo/muduo.git +cd muduo +mkdir build +cd build +cmake .. +make -12 + +#准备lib里的内容 + + +cd /home/server +#rapidjson库 + +git clone https://github.com/Tencent/rapidjson.git +cd rapidjson +mkdir build +cd build +cmake .. +make -j12 +make install + +#准备包(package) + +cd /home/server +#nanodbc库 + +#准备mariadb(已准备) + +#下载unixodbc +apt install unixodbc + +#下载odbc_config +tar -xzvf unixODBC-2.3.9.tar.gz +cd unixODBC-2.3.9.tar.gz +./configure --enable-gui=no +make +sudo make install +odbc_config --version #check odbc_config is installed + +#下载odbc_mariadb +apt install odbc-mariadb + + +#配置odbc_mariadb +### configure odbc-mariadb + +see complete info on "https://mariadb.com/kb/en/creating-a-data-source-with-mariadb-connectorodbc/" + +[MariaDB ODBC 3.0 Driver] +Description = MariaDB Connector/ODBC v.3.0 +Driver=/usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so + + +cd /home/server +#下载nanodbc库 +git clone https://github.com/nanodbc/nanodbc.git +cd nanodbc +mkdir build +cd build +cmake .. +make -j12 +make install + +cd /home/server +#准备好 +cp ./muduo/build/lib/*.a ./cids-pack/Lib/ + +cd /cids-pack +mkdir build +cmake .. +make -j12 + diff --git a/test_driver/client_bootstrap.csc b/test_driver/client_bootstrap.csc index c8c84b8..c7fd4e5 100644 --- a/test_driver/client_bootstrap.csc +++ b/test_driver/client_bootstrap.csc @@ -11,18 +11,12 @@ var uuid = "0x46a8e4d9515650e4"hex.shift_left(8) var reconnect_time = 0 function send_bootstrap() - var header = uuid.logic_or(bitset.from_number(reconnect_time)) - system.out.println(header.to_string()) - var header_str = new string - foreach i in range(8) - header_str += char.from_ascii(header.logic_and("0xFF"hex).to_number()) - header = header.shift_right(8) - end + var header = "0011000100110001001100010011000100110001001100010011001000110000" var sock = new net.udp.socket sock.open_v4() - foreach i in range(10) do sock.send_to(header_str, server_ep) + foreach i in range(10) do sock.send_to(header, server_ep) try - return runtime.wait_until(100, sock.receive_from, {32, server_ep}) + return runtime.wait_until(100, sock.receive_from, {128, server_ep}) catch e if reconnect_time < 254 ++reconnect_time @@ -36,5 +30,7 @@ loop if ip != null system.out.println("Get: " + ip + ", Reconnect Time: " + reconnect_time) break + else + system.out.println("failed get ip") end end \ No newline at end of file From 8cec589ee001fffdeb501b459f8ff5d51a30d465 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 Date: Thu, 10 Jun 2021 14:55:39 +0800 Subject: [PATCH 13/16] update --- .gitignore | 7 ++- Src/Center/Center.cpp | 77 ++++++++++++++++++++------------ Src/Common/Udp.cpp | 2 - Src/Mirror/Mirror.cpp | 62 +++++++++++-------------- include/Common/Telemeter.hpp | 5 ++- include/Common/Udp.hpp | 4 +- test_driver/client_bootstrap.csc | 2 +- 7 files changed, 84 insertions(+), 75 deletions(-) delete mode 100644 Src/Common/Udp.cpp diff --git a/.gitignore b/.gitignore index 433a520..614b7fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ build/ -lib/ -.idea/ -cmake-build-debug/ -Lib/ \ No newline at end of file +.idea +cmake-build-debug +Lib \ No newline at end of file diff --git a/Src/Center/Center.cpp b/Src/Center/Center.cpp index 1346f24..ecf12bd 100644 --- a/Src/Center/Center.cpp +++ b/Src/Center/Center.cpp @@ -111,9 +111,9 @@ void center::wait_cli_login() }; //用于接收数据的缓冲区 - std::array packet {0}; - std::array uidbuf {0}; - std::array statebuf {0}; + std::array packet {0}; + std::array uidbuf {0}; + std::array statebuf {0}; //创建socket int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); //服务端addr和客户端addr, 后者保存发送方的信息 @@ -142,20 +142,26 @@ void center::wait_cli_login() //线程主循环 while(true) { - int recv_num = recvfrom(sock_fd, packet.data(), packet.size(), MSG_WAITALL, (sockaddr*)&addr_cli, &place_holder_1); + char recv_buf[8]; + memset(recv_buf, 0, sizeof(recv_buf)); + int recv_num = recvfrom(sock_fd,recv_buf, protocol::kCLI_LOGIN_PACSIZE_, MSG_WAITALL, (sockaddr*)&addr_cli, &place_holder_1); //MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。 //如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。 //可能是阻塞超时, 进行下次循环 - if(recv_num < 0) + if(recv_num < 0){ + LOG_WARN << "recv from client error"; continue; + } + for(int i = 0; i < 8; i++) + packet[i] = recv_buf[i]; //按照协议格式进行解析, 并且得到ip等其他信息 - memcpy(uidbuf.data(), packet.data(), protocal::kCLI_LOGIN_UID_); + memcpy(uidbuf.data(), packet.data(), protocol::kCLI_LOGIN_UID_); for(auto& ch :uidbuf) ch += '0'; size_t uid = std::atol(uidbuf.data()); - memcpy(statebuf.data(), packet.data() + protocal::kCLI_LOGIN_UID_, protocal::kCLI_LOGIN_STATE_); + memcpy(statebuf.data(), packet.data() + protocol::kCLI_LOGIN_UID_, protocol::kCLI_LOGIN_STATE_); size_t state = statebuf[0]; //state暂时不做处理 @@ -205,7 +211,8 @@ void center::wait_cli_login() else if(this->mirs_data_.size() == 1) available_mir = (*mirs_data_.begin()).first; //回复可用mir地址 - int send_num = sendto(sock_fd, &available_mir, sizeof(available_mir), 0, (sockaddr*)&addr_cli, sizeof(addr_cli)); + char send_buf[4] = {available_mir.seg0,available_mir.seg1,available_mir.seg2,available_mir.seg3}; + int send_num = sendto(sock_fd, send_buf, protocol::kCENT_RESPONSE_PACSIZE_, 0, (sockaddr*)&addr_cli, sizeof(addr_cli)); login_count++; //数据库记录日志 @@ -228,7 +235,7 @@ void center::wait_cli_login() atom_mutex_ = false; //设置一段时间后pop掉队头的任务 - this->pool_.run( [this](){ + this->pool_.run( [this, &uid](){ sleep(telemeter::setting->cli_login_cache_time_); while(true) { @@ -240,8 +247,11 @@ void center::wait_cli_login() atom_mutex_ = false; LOG_INFO << "erase login cache of client: " << id; } - else + else{ + LOG_INFO << "cached client login, no reply for client: " << uid; continue; + } + } }); break; @@ -271,9 +281,9 @@ void center::listen_mir_beat() size_t all_beat_count {0}; //用于判活算法 //用于接收数据的缓冲区 - std::array packet {0}; - std::array ipbuf {0}; - std::array loadbuf {0}; + std::array packet {0}; + std::array ipbuf {0}; + std::array loadbuf {0}; //创建socket int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); //服务端addr和客户端addr, 后者保存发送方的信息 @@ -298,19 +308,28 @@ void center::listen_mir_beat() //线程主循环 while(true) { - int recv_num = recvfrom(sock_fd, packet.data(), packet.size(), MSG_WAITALL, (sockaddr*)&addr_mir, &place_holder_1); + char recv_buf[8] = {0}; + memset(recv_buf, 0, sizeof(recv_buf)); + int recv_num = recvfrom(sock_fd, recv_buf, protocol::kMIR_BEAT_PACSIZE_, MSG_WAITALL, (sockaddr*)&addr_mir, &place_holder_1); //MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。 //如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。 //可能是阻塞超时, 进行下次循环 - if(recv_num < 0) + if(recv_num < 0) { + LOG_WARN << "recv from mirror error"; continue; + } + for(int i = 0; i < 8; i++) + packet[i] = recv_buf[i]; //按照协议格式进行解析, 并且得到ip等其他信息 - memcpy(ipbuf.data(), packet.data(), protocal::kMIR_BEAT_IP_); - memcpy(loadbuf.data(), packet.data() + protocal::kMIR_BEAT_IP_, protocal::kMIR_BEAT_LOAD_); + memcpy(ipbuf.data(), packet.data(), protocol::kMIR_BEAT_IP_); + + memcpy(loadbuf.data(), packet.data() + protocol::kMIR_BEAT_IP_, protocol::kMIR_BEAT_LOAD_); + + mir_ip = IP(ipbuf[0], ipbuf[1], ipbuf[2], ipbuf[3]); + LOG_INFO << mir_ip.to_string() << " send packet " << packet.data(); - mir_ip = (ipbuf[0] << 24) + (ipbuf[1] << 16) + (ipbuf[2] << 8) + (ipbuf[3]); if(mirs_data_.count(mir_ip) == 0) { mirs_data_.insert({mir_ip, MirDescript()}); @@ -324,17 +343,17 @@ void center::listen_mir_beat() all_beat_count++; if(all_beat_count >= mirs_data_.size() - 1) { - for(auto& kvp : mirs_data_) - { - if(kvp.second.decre_and_get_beat() <= 0); - { - //说明有mir掉线了 - int i = 3; //占位避免编译器报warning - //dblog(MIR_DISCONECT); - mirs_data_.erase(kvp.first); - LOG_INFO << "mirror disconnect: " << const_cast(&kvp.first)->to_string(); - } - } +// for(auto& kvp : mirs_data_) +// { +// if(kvp.second.decre_and_get_beat() <= 0); +// { +// //说明有mir掉线了 +// int i = 3; //占位避免编译器报warning +// //dblog(MIR_DISCONECT); +// mirs_data_.erase(kvp.first); +// LOG_INFO << "mirror disconnect: " << const_cast(&kvp.first)->to_string(); +// } +// } } } diff --git a/Src/Common/Udp.cpp b/Src/Common/Udp.cpp deleted file mode 100644 index cff7dec..0000000 --- a/Src/Common/Udp.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include - diff --git a/Src/Mirror/Mirror.cpp b/Src/Mirror/Mirror.cpp index 3a57dac..086ac45 100644 --- a/Src/Mirror/Mirror.cpp +++ b/Src/Mirror/Mirror.cpp @@ -49,6 +49,8 @@ void Mirror::init() { telemeter::setting->db_password = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); else if (line.find("center_ip") != std::string::npos) telemeter::setting->center_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("this_ip") != std::string::npos) + telemeter::setting->this_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); else if (line.find("update_pic_interval") != std::string::npos) telemeter::setting->update_pic_interval = std::stoi( std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); @@ -107,6 +109,8 @@ void Mirror::init() { void Mirror::start() { + + //初始化配置文件及各数据 this->init(); @@ -152,15 +156,23 @@ void Mirror::start() { void Mirror::update_data_info() { -// 发送ip地址 -// using Server::IP; + + // 发送‘心跳包’ + int sock; + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + std::cerr << "sock error" << std::endl; + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; +// 设置发送端口 + servaddr.sin_port = htons(port::kMIR_BEAT_); +// 设置发送ip +/*修改:若发送失败,则沿用之前的ip*/ + servaddr.sin_addr.s_addr = inet_addr((telemeter::setting->center_ip).c_str()); // 更新间隔 size_t time = 0; - - unsigned char this_ip[4] = {'0', '0', '0', '0'};//解析ip - - // 发送的息 + // 发送消息 char send_buf[8] = {0}; // 定义计算服务器负载情况的函数 auto cal_ser_load = [&]() -> uint8_t { @@ -181,14 +193,7 @@ void Mirror::update_data_info() { auto get_packet = [&]() { -// getMyip - std::string host; - std::string ip; - bool err = GetHostInfo(host, ip); - if (!err) { - //报错 - } - IP this_ip(ip); + IP this_ip(telemeter::setting->this_ip); //calculate ServerLoad unsigned char serverLoad = cal_ser_load(); @@ -238,37 +243,20 @@ void Mirror::update_data_info() { //to_string(8byte) = 4+1+1+1+1 true/false //重置缓冲 memset(send_buf, 0, sizeof(send_buf)); - //获取负载情况 std::vector info = get_packet(); - //更新负载情况 for (int i = 0; i < 7; i++) send_buf[i] = info[i]; - //最后位填充0 send_buf[7] = '\0'; - //重置time time = 1; - LOG_INFO << "update pack"; } -// 发送‘心跳包’ - int sock; - if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - std::cerr << "sock error" << std::endl; - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(servaddr)); - servaddr.sin_family = AF_INET; -// 设置发送端口 - servaddr.sin_port = htons(port::kMIR_BEAT_); -// 设置发送ip -/*修改:若发送失败,则沿用之前的ip*/ - servaddr.sin_addr.s_addr = inet_addr((telemeter::setting->center_ip).c_str()); // 发送缓存 - sendto(sock, send_buf, strlen(send_buf), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); + sendto(sock, send_buf, protocol::kMIR_BEAT_PACSIZE_, 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); // 统计发送心跳包次数 time++; //心跳包频率 @@ -313,6 +301,8 @@ void Mirror::read_config() { set.db_password = std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']')); else if (line.find("center_ip") != std::string::npos) set.center_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("this_ip") != std::string::npos) + telemeter::setting->this_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); else if (line.find("update_pic_interval") != std::string::npos) set.update_pic_interval = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); else if (line.find("utc_time: ") != std::string::npos) @@ -536,7 +526,7 @@ void Mirror::on_message(const muduo::net::TcpConnectionPtr &connectionPtr, next_event = false; - std::string pic_url = telemeter::setting->img_path + "/" + db_control::find_pic(this->conn, id) + ".jpg"; + std::string pic_url = "http://" + telemeter::setting->this_ip + ":" + std::to_string(port::kMIR_HTTP_) + telemeter::setting->img_path + "/" + db_control::find_pic(this->conn, id) + ".jpg"; std::deque msgs = db_control::find_mes(this->conn, id, std::to_string(stamp)); //统一utc时间 @@ -554,9 +544,11 @@ void Mirror::on_message(const muduo::net::TcpConnectionPtr &connectionPtr, msgs_hash.push_back(std::hash()(*iter)); } - if (new_hash == old) + if (new_hash == old) { connectionPtr->send(json_control::no_need_update); - else { + + }else { + cli_info_[id] = new_hash; ClassMes sendInfo; sendInfo.image_url = pic_url; sendInfo.messages = msgs; diff --git a/include/Common/Telemeter.hpp b/include/Common/Telemeter.hpp index e36e52c..745f667 100644 --- a/include/Common/Telemeter.hpp +++ b/include/Common/Telemeter.hpp @@ -66,6 +66,7 @@ struct Setting std::string db_user; std::string db_password; std::string center_ip; + std::string this_ip; int update_pic_interval; int utc_time; std::string update_calendar_time; @@ -108,8 +109,8 @@ namespace telemeter { #endif #ifdef SRC_MIRROR_H - static Setting _set_cache_one = {1, 60, "home/jol", "Scucids-server","teacher","zhirui208+", "192.168.233.14", 6,8,"24:00","24:00",60}; - static Setting _set_cache_two = {1, 60, "home/jol", "Scucids-server","teacher","zhirui208+", "192.168.233.14", 6,8,"24:00","24:00",60}; + static Setting _set_cache_one = {1, 60, "/var/www/html/images", "Scucids-server","teacher","zhirui208+", "192.168.233.14","192.168.233.13", 6,8,"24:00","24:00",60}; + static Setting _set_cache_two = {1, 60, "/var/www/html/images", "Scucids-server","teacher","zhirui208+", "192.168.233.14", "192.168.233.13",6,8,"24:00","24:00",60}; //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 static Setting* setting = &_set_cache_one; static Setting* setting_copy = &_set_cache_two; diff --git a/include/Common/Udp.hpp b/include/Common/Udp.hpp index c0629a1..96b3624 100644 --- a/include/Common/Udp.hpp +++ b/include/Common/Udp.hpp @@ -24,10 +24,10 @@ namespace port const constexpr size_t kCLI_LOGIN_ = 20800; const constexpr size_t kCLI_BEAT_ = 20801; const constexpr size_t kMIR_BEAT_ = 20802; - const constexpr size_t kINS_MSG_ = 20803; + const constexpr size_t kMIR_HTTP_ = 20803; } -namespace protocal +namespace protocol { //以字节计算的每个包的大小和协议中每一部分的大小, 二级缩进的和应该等于第一级缩进 const constexpr size_t kCLI_LOGIN_PACSIZE_ = 8; diff --git a/test_driver/client_bootstrap.csc b/test_driver/client_bootstrap.csc index c7fd4e5..743e600 100644 --- a/test_driver/client_bootstrap.csc +++ b/test_driver/client_bootstrap.csc @@ -11,7 +11,7 @@ var uuid = "0x46a8e4d9515650e4"hex.shift_left(8) var reconnect_time = 0 function send_bootstrap() - var header = "0011000100110001001100010011000100110001001100010011001000110000" + var header = "12345670" var sock = new net.udp.socket sock.open_v4() foreach i in range(10) do sock.send_to(header, server_ep) From 4c80f1e4a6cedf267def90ec882ec545990b75ca Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <41978171+jin1xiao3long2@users.noreply.github.com> Date: Sat, 21 Aug 2021 14:54:53 +0800 Subject: [PATCH 14/16] Update step.md --- step.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/step.md b/step.md index 7a1c48d..19f4655 100644 --- a/step.md +++ b/step.md @@ -4,12 +4,12 @@ sudo -s (**you passwd**) * 基本工具 -apt update -apt upgrade -apt install g++ -apt install cmake -apt install make -apt install git +apt update +apt upgrade +apt install g++ +apt install cmake +apt install make +apt install git * 准备环境 cd home From 6f01709a12043848a0925cf14ad2102031f81765 Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <41978171+jin1xiao3long2@users.noreply.github.com> Date: Sat, 21 Aug 2021 14:57:36 +0800 Subject: [PATCH 15/16] Update step.md --- step.md | 102 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/step.md b/step.md index 19f4655..94d6500 100644 --- a/step.md +++ b/step.md @@ -12,91 +12,91 @@ apt install make apt install git * 准备环境 -cd home -mkdir server -cd server +cd home +mkdir server +cd server * 准备第三方库 - #下载boost库 -tar -jxvpf boost_1_74_0.tar.bz2 -cd boost_1_74_0 -./bootstrap.sh --with-libraries=all --with-toolset=gcc -./b2 install + # 下载boost库 +tar -jxvpf boost_1_74_0.tar.bz2 +cd boost_1_74_0 +./bootstrap.sh --with-libraries=all --with-toolset=gcc +./b2 install cd /home/server # muduo库 -git clone https://github.com/chenshuo/muduo.git -cd muduo -mkdir build -cd build -cmake .. -make -12 +git clone https://github.com/chenshuo/muduo.git +cd muduo +mkdir build +cd build +cmake .. +make -12 -#准备lib里的内容 +# 准备lib里的内容 -cd /home/server -#rapidjson库 +cd /home/server +# rapidjson库 git clone https://github.com/Tencent/rapidjson.git -cd rapidjson -mkdir build -cd build -cmake .. -make -j12 -make install +cd rapidjson +mkdir build +cd build +cmake .. +make -j12 +make install -#准备包(package) +# 准备包(package) cd /home/server -#nanodbc库 +# nanodbc库 -#准备mariadb(已准备) +# 准备mariadb(已准备) -#下载unixodbc +# 下载unixodbc apt install unixodbc #下载odbc_config -tar -xzvf unixODBC-2.3.9.tar.gz -cd unixODBC-2.3.9.tar.gz -./configure --enable-gui=no -make -sudo make install -odbc_config --version #check odbc_config is installed - -#下载odbc_mariadb +tar -xzvf unixODBC-2.3.9.tar.gz +cd unixODBC-2.3.9.tar.gz +./configure --enable-gui=no +make +sudo make install +odbc_config --version #check odbc_config is installed + +# 下载odbc_mariadb apt install odbc-mariadb -#配置odbc_mariadb +# 配置odbc_mariadb ### configure odbc-mariadb see complete info on "https://mariadb.com/kb/en/creating-a-data-source-with-mariadb-connectorodbc/" [MariaDB ODBC 3.0 Driver] -Description = MariaDB Connector/ODBC v.3.0 -Driver=/usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so +Description = MariaDB Connector/ODBC v.3.0 +Driver=/usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so -cd /home/server -#下载nanodbc库 +cd /home/server +# 下载nanodbc库 git clone https://github.com/nanodbc/nanodbc.git -cd nanodbc -mkdir build -cd build -cmake .. -make -j12 -make install +cd nanodbc +mkdir build +cd build +cmake .. +make -j12 +make install cd /home/server -#准备好 +# 准备好 cp ./muduo/build/lib/*.a ./cids-pack/Lib/ -cd /cids-pack -mkdir build -cmake .. -make -j12 +cd /cids-pack +mkdir build +cmake .. +make -j12 From fd2d7109e66039a66011b8cc46abdc5c56759b0e Mon Sep 17 00:00:00 2001 From: jin1xiao3long2 <41978171+jin1xiao3long2@users.noreply.github.com> Date: Sun, 17 Oct 2021 19:26:29 +0800 Subject: [PATCH 16/16] Update step.md --- step.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/step.md b/step.md index 94d6500..8dc8973 100644 --- a/step.md +++ b/step.md @@ -61,7 +61,7 @@ apt install unixodbc #下载odbc_config tar -xzvf unixODBC-2.3.9.tar.gz -cd unixODBC-2.3.9.tar.gz +cd unixODBC-2.3.9 ./configure --enable-gui=no make sudo make install