Bladeren bron

删除hiredis,添加cppredis

dev
homeremote 5 jaren geleden
bovenliggende
commit
acf5e4d482
96 gewijzigde bestanden met toevoegingen van 8136 en 10890 verwijderingen
  1. +92
    -0
      俱乐部/Platform.sln
  2. +1
    -0
      俱乐部/Source/ServerControl/CorrespondServer/ServiceUnits.cpp
  3. +144
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/array_builder.hpp
  4. +69
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builder_iface.hpp
  5. +48
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builders_factory.hpp
  6. +117
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/bulk_string_builder.hpp
  7. +106
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/error_builder.hpp
  8. +119
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/integer_builder.hpp
  9. +139
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/reply_builder.hpp
  10. +113
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/simple_string_builder.hpp
  11. +2369
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/client.hpp
  12. +134
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/consumer.hpp
  13. +288
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/reply.hpp
  14. +420
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/sentinel.hpp
  15. +523
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/subscriber.hpp
  16. +183
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/types.hpp
  17. +42
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/cpp_redis
  18. +41
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/generate_rand.hpp
  19. +130
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/variadic_template.hpp
  20. +131
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/client.ipp
  21. +157
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/types.hpp
  22. +48
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/convert.hpp
  23. +10
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/deprecated.hpp
  24. +91
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/dispatch_queue.hpp
  25. +56
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/error.hpp
  26. +258
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/logger.hpp
  27. +31
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/macro.hpp
  28. +76
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/optional.hpp
  29. +219
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/redis_connection.hpp
  30. +128
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client.hpp
  31. +200
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client_iface.hpp
  32. +265
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/io_service.hpp
  33. +90
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/self_pipe.hpp
  34. +330
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_client.hpp
  35. +175
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_server.hpp
  36. +223
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_socket.hpp
  37. +40
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/tacopie
  38. +78
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/error.hpp
  39. +215
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/logger.hpp
  40. +169
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/thread_pool.hpp
  41. +46
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/typedefs.hpp
  42. +22
    -0
      俱乐部/Source/ServerControl/CppRedis/includes/winsock_initializer.h
  43. BIN
      俱乐部/Source/ServerControl/KernelEngine/Debug_Unicode/vc142.pdb
  44. +0
    -8
      俱乐部/Source/hiredis/.gitignore
  45. +0
    -97
      俱乐部/Source/hiredis/.travis.yml
  46. +0
    -199
      俱乐部/Source/hiredis/CHANGELOG.md
  47. +0
    -29
      俱乐部/Source/hiredis/COPYING
  48. +0
    -274
      俱乐部/Source/hiredis/Makefile
  49. +0
    -470
      俱乐部/Source/hiredis/README.md
  50. +0
    -127
      俱乐部/Source/hiredis/adapters/ae.h
  51. +0
    -153
      俱乐部/Source/hiredis/adapters/glib.h
  52. +0
    -81
      俱乐部/Source/hiredis/adapters/ivykis.h
  53. +0
    -147
      俱乐部/Source/hiredis/adapters/libev.h
  54. +0
    -172
      俱乐部/Source/hiredis/adapters/libevent.h
  55. +0
    -119
      俱乐部/Source/hiredis/adapters/libuv.h
  56. +0
    -114
      俱乐部/Source/hiredis/adapters/macosx.h
  57. +0
    -135
      俱乐部/Source/hiredis/adapters/qt.h
  58. +0
    -65
      俱乐部/Source/hiredis/alloc.c
  59. +0
    -44
      俱乐部/Source/hiredis/alloc.h
  60. +0
    -24
      俱乐部/Source/hiredis/appveyor.yml
  61. +0
    -767
      俱乐部/Source/hiredis/async.c
  62. +0
    -142
      俱乐部/Source/hiredis/async.h
  63. +0
    -72
      俱乐部/Source/hiredis/async_private.h
  64. +0
    -339
      俱乐部/Source/hiredis/dict.c
  65. +0
    -126
      俱乐部/Source/hiredis/dict.h
  66. +0
    -62
      俱乐部/Source/hiredis/examples/example-ae.c
  67. +0
    -73
      俱乐部/Source/hiredis/examples/example-glib.c
  68. +0
    -58
      俱乐部/Source/hiredis/examples/example-ivykis.c
  69. +0
    -52
      俱乐部/Source/hiredis/examples/example-libev.c
  70. +0
    -73
      俱乐部/Source/hiredis/examples/example-libevent-ssl.c
  71. +0
    -64
      俱乐部/Source/hiredis/examples/example-libevent.c
  72. +0
    -53
      俱乐部/Source/hiredis/examples/example-libuv.c
  73. +0
    -66
      俱乐部/Source/hiredis/examples/example-macosx.c
  74. +0
    -46
      俱乐部/Source/hiredis/examples/example-qt.cpp
  75. +0
    -32
      俱乐部/Source/hiredis/examples/example-qt.h
  76. +0
    -97
      俱乐部/Source/hiredis/examples/example-ssl.c
  77. +0
    -91
      俱乐部/Source/hiredis/examples/example.c
  78. +0
    -12
      俱乐部/Source/hiredis/fmacros.h
  79. +0
    -1078
      俱乐部/Source/hiredis/hiredis.c
  80. +0
    -298
      俱乐部/Source/hiredis/hiredis.h
  81. +0
    -11
      俱乐部/Source/hiredis/hiredis.pc.in
  82. +0
    -53
      俱乐部/Source/hiredis/hiredis_ssl.h
  83. +0
    -12
      俱乐部/Source/hiredis/hiredis_ssl.pc.in
  84. +0
    -571
      俱乐部/Source/hiredis/net.c
  85. +0
    -54
      俱乐部/Source/hiredis/net.h
  86. +0
    -669
      俱乐部/Source/hiredis/read.c
  87. +0
    -122
      俱乐部/Source/hiredis/read.h
  88. +0
    -1291
      俱乐部/Source/hiredis/sds.c
  89. +0
    -276
      俱乐部/Source/hiredis/sds.h
  90. +0
    -42
      俱乐部/Source/hiredis/sdsalloc.h
  91. +0
    -248
      俱乐部/Source/hiredis/sockcompat.c
  92. +0
    -91
      俱乐部/Source/hiredis/sockcompat.h
  93. +0
    -448
      俱乐部/Source/hiredis/ssl.c
  94. +0
    -1017
      俱乐部/Source/hiredis/test.c
  95. +0
    -70
      俱乐部/Source/hiredis/test.sh
  96. +0
    -56
      俱乐部/Source/hiredis/win32.h

+ 92
- 0
俱乐部/Platform.sln Bestand weergeven

@@ -33,78 +33,170 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug_Unicode|Win32 = Debug_Unicode|Win32
Debug_Unicode|x64 = Debug_Unicode|x64
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release_Unicode|Win32 = Release_Unicode|Win32
Release_Unicode|x64 = Release_Unicode|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Debug|x64.Build.0 = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|Win32.Build.0 = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|x64.ActiveCfg = Release_Unicode|Win32
{5266973A-47AE-481C-BD4B-06E5DB08A99B}.Release|x64.Build.0 = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Debug|x64.Build.0 = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|Win32.Build.0 = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|x64.ActiveCfg = Release_Unicode|Win32
{CCD2D328-1912-4FC4-91B5-2333A7EF6EB7}.Release|x64.Build.0 = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Debug|x64.Build.0 = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|Win32.Build.0 = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|x64.ActiveCfg = Release_Unicode|Win32
{51FD2060-F4F9-4982-8474-473541D4FCF8}.Release|x64.Build.0 = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Debug|x64.Build.0 = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|Win32.Build.0 = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|x64.ActiveCfg = Release_Unicode|Win32
{C38EABE4-E7E3-437A-8ECF-97A8626227D0}.Release|x64.Build.0 = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Debug|x64.Build.0 = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Release|Win32.Build.0 = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Release|x64.ActiveCfg = Release_Unicode|Win32
{DA531A23-506A-4643-BA47-B77542C5F41C}.Release|x64.Build.0 = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Debug|x64.Build.0 = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Release|Win32.Build.0 = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Release|x64.ActiveCfg = Release_Unicode|Win32
{74DE8924-75DC-4444-AB26-B687F71BD778}.Release|x64.Build.0 = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Debug|x64.Build.0 = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|Win32.Build.0 = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|x64.ActiveCfg = Release_Unicode|Win32
{C323A106-B50D-48CB-A353-CFBE5308F2A5}.Release|x64.Build.0 = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Debug|x64.Build.0 = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|Win32.Build.0 = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|x64.ActiveCfg = Release_Unicode|Win32
{660F9BCF-23A3-425A-9BDC-40D7AFBC8DFB}.Release|x64.Build.0 = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Debug|x64.Build.0 = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|Win32.Build.0 = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|x64.ActiveCfg = Release_Unicode|Win32
{60710DEB-8538-4CB6-8ABA-3A143E451C21}.Release|x64.Build.0 = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|x64.ActiveCfg = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Debug|x64.Build.0 = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release_Unicode|x64.ActiveCfg = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|Win32.Build.0 = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|x64.ActiveCfg = Release_Unicode|Win32
{B4766ADF-5AA6-4ADF-9354-4F889FFF028E}.Release|x64.Build.0 = Release_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|Win32.ActiveCfg = Debug_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|Win32.Build.0 = Debug_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|x64.ActiveCfg = Debug_Unicode|x64
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug_Unicode|x64.Build.0 = Debug_Unicode|x64
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|Win32.ActiveCfg = Debug_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|Win32.Build.0 = Debug_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|x64.ActiveCfg = Debug_Unicode|x64
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Debug|x64.Build.0 = Debug_Unicode|x64
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|Win32.ActiveCfg = Release_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|Win32.Build.0 = Release_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|x64.ActiveCfg = Release_Unicode|x64
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release_Unicode|x64.Build.0 = Release_Unicode|x64
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|Win32.ActiveCfg = Release_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|Win32.Build.0 = Release_Unicode|Win32
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|x64.ActiveCfg = Release_Unicode|x64
{A24A269E-D5C3-4D96-B5D3-A254D91F617D}.Release|x64.Build.0 = Release_Unicode|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE


+ 1
- 0
俱乐部/Source/ServerControl/CorrespondServer/ServiceUnits.cpp Bestand weergeven

@@ -111,6 +111,7 @@ bool CServiceUnits::InitializeService()
WORD wServicePort = m_InitParameter.m_wServicePort;
if (m_TCPNetworkEngine->SetServiceParameter(wServicePort, wMaxConnect, szCompilation) == false) return false;
//
return true;
}


+ 144
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/array_builder.hpp Bestand weergeven

@@ -0,0 +1,144 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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 CPP_REDIS_BUILDERS_ARRAY_BUILDER_HPP_
#define CPP_REDIS_BUILDERS_ARRAY_BUILDER_HPP_

#include <cpp_redis/builders/builder_iface.hpp>
#include <cpp_redis/builders/integer_builder.hpp>
#include <cpp_redis/core/reply.hpp>

namespace cpp_redis {

namespace builders {

/**
* builder to build redis array replies
*
*/
class array_builder : public builder_iface {
public:
/**
* ctor
*
*/
array_builder();

/**
* dtor
*
*/
~array_builder() override = default;

/**
* copy ctor
*
*/
array_builder(const array_builder &) = delete;

/**
* assignment operator
*
*/
array_builder &operator=(const array_builder &) = delete;

public:
/**
* take data as parameter which is consumed to build the reply
* every bytes used to build the reply must be removed from the buffer passed as parameter
*
* @param data data to be consumed
* @return current instance
*
*/
builder_iface &operator<<(std::string &data) override;

/**
* @return whether the reply could be built
*
*/
bool reply_ready() const override;

/**
* @return reply object
*
*/
reply get_reply() const override;

private:
/**
* take data as parameter which is consumed to determine array size
* every bytes used to build size is removed from the buffer passed as parameter
*
* @param buffer data to be consumer
* @return true if the size could be found
*
*/
bool fetch_array_size(std::string &buffer);

/**
* take data as parameter which is consumed to build an array row
* every bytes used to build row is removed from the buffer passed as parameter
*
* @param buffer data to be consumer
* @return true if the row could be built
*
*/
bool build_row(std::string &buffer);

private:
/**
* builder used to fetch the array size
*
*/
integer_builder m_int_builder;

/**
* built array size
*
*/
uint64_t m_array_size;

/**
* current builder used to build current row
*
*/
std::unique_ptr<builder_iface> m_current_builder;

/**
* whether the reply is ready or not
*
*/
bool m_reply_ready;

/**
* reply to be built (or built)
*
*/
reply m_reply;
};

} // namespace builders

} // namespace cpp_redis

#endif

+ 69
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builder_iface.hpp Bestand weergeven

@@ -0,0 +1,69 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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 CPP_REDIS_BUILDERS_BUILDER_IFACE_HPP_
#define CPP_REDIS_BUILDERS_BUILDER_IFACE_HPP_

#include <memory>
#include <string>

#include <cpp_redis/core/reply.hpp>

namespace cpp_redis {

namespace builders {

/**
* @brief interface inherited by all builders
*/
class builder_iface {
public:
virtual ~builder_iface() = default;

/**
* take data as parameter which is consumed to build the reply
* every bytes used to build the reply must be removed from the buffer passed as parameter
*
* @param data data to be consumed
* @return current instance
*
*/
virtual builder_iface &operator<<(std::string &data) = 0;

/**
* @return whether the reply could be built
*
*/
virtual bool reply_ready() const = 0;

/**
* @return reply object
*
*/
virtual reply get_reply() const = 0;
};

} // namespace builders

} // namespace cpp_redis

#endif

+ 48
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/builders_factory.hpp Bestand weergeven

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <memory>

#include <cpp_redis/builders/builder_iface.hpp>

namespace cpp_redis {

namespace builders {

/**
* create a builder corresponding to the given id
* * + for simple strings
* * - for errors
* * : for integers
* * $ for bulk strings
* * * for arrays
*
* @param id char that determines which builder to return
* @return new builder instance depending on id value
*/
std::unique_ptr<builder_iface> create_builder(char id);

} // namespace builders

} // namespace cpp_redis

+ 117
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/bulk_string_builder.hpp Bestand weergeven

@@ -0,0 +1,117 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <cpp_redis/builders/builder_iface.hpp>
#include <cpp_redis/builders/integer_builder.hpp>
#include <cpp_redis/core/reply.hpp>

namespace cpp_redis {

namespace builders {

//!
//! builder to build redis bulk string replies
//!
class bulk_string_builder : public builder_iface {
public:
//! ctor
bulk_string_builder();
//! dtor
~bulk_string_builder() override = default;

//! copy ctor
bulk_string_builder(const bulk_string_builder&) = delete;
//! assignment operator
bulk_string_builder& operator=(const bulk_string_builder&) = delete;

public:
//!
//! take data as parameter which is consumed to build the reply
//! every bytes used to build the reply must be removed from the buffer passed as parameter
//!
//! @param data data to be consumed
//! @return current instance
//!
builder_iface& operator<<(std::string& data) override;

//!
//! @return whether the reply could be built
//!
bool reply_ready() const override;

//!
//! @return reply object
//!
reply get_reply() const override;

//!
//! @return the parsed bulk string
//!
const std::string& get_bulk_string() const;

//!
//! @return whether the bulk string is null
//!
bool is_null() const;

private:
void build_reply();
bool fetch_size(std::string& str);
void fetch_str(std::string& str);

private:
//!
//! builder used to get bulk string size
//!
integer_builder m_int_builder;

//!
//! bulk string size
//!
int m_str_size;

//!
//! bulk string
//!
std::string m_str;

//!
//! whether the bulk string is null
//!
bool m_is_null;

//!
//! whether the reply is ready or not
//!
bool m_reply_ready;

//!
//! reply to be built
//!
reply m_reply;
};

} // namespace builders

} // namespace cpp_redis

+ 106
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/error_builder.hpp Bestand weergeven

@@ -0,0 +1,106 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <cpp_redis/builders/builder_iface.hpp>
#include <cpp_redis/builders/simple_string_builder.hpp>
#include <cpp_redis/core/reply.hpp>

namespace cpp_redis {

namespace builders {

/**
* builder to build redis error replies
*
*/
class error_builder : public builder_iface {
public:
/**
* ctor
*
*/
error_builder() = default;
/**
* dtor
*
*/
~error_builder() override = default;

/**
* copy ctor
*
*/
error_builder(const error_builder&) = delete;
/**
* assignment operator
*
*/
error_builder& operator=(const error_builder&) = delete;

public:
/**
* take data as parameter which is consumed to build the reply
* every bytes used to build the reply must be removed from the buffer passed as parameter
*
* @param data data to be consumed
* @return current instance
*
*/
builder_iface& operator<<(std::string& data) override;

/**
* @return whether the reply could be built
*
*/
bool reply_ready() const override;

/**
* @return reply object
*
*/
reply get_reply() const override;

/**
* @return the parsed error
*
*/
const std::string& get_error() const;

private:
/**
* builder used to parse the error
*
*/
simple_string_builder m_string_builder;

/**
* reply to be built
*
*/
reply m_reply;
};

} // namespace builders

} // namespace cpp_redis

+ 119
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/integer_builder.hpp Bestand weergeven

@@ -0,0 +1,119 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <cpp_redis/builders/builder_iface.hpp>
#include <cpp_redis/core/reply.hpp>

#include <cstdint>

namespace cpp_redis {

namespace builders {

/**
* builder to build redis integer replies
*
*/
class integer_builder : public builder_iface {
public:
/**
* ctor
*
*/
integer_builder();
/**
* dtor
*
*/
~integer_builder() override = default;

/**
* copy ctor
*
*/
integer_builder(const integer_builder&) = delete;
/**
* assignment operator
*
*/
integer_builder& operator=(const integer_builder&) = delete;

public:
/**
* take data as parameter which is consumed to build the reply
* every bytes used to build the reply must be removed from the buffer passed as parameter
*
* @param data data to be consumed
* @return current instance
*
*/
builder_iface& operator<<(std::string& data) override;

/**
* @return whether the reply could be built
*
*/
bool reply_ready() const override;

/**
* @return reply object
*
*/
reply get_reply() const override;

/**
* @return the parsed integer
*
*/
int64_t get_integer() const;

private:
/**
* parsed number
*
*/
int64_t m_nbr;

/**
* -1 for negative number, 1 otherwise
*
*/
int64_t m_negative_multiplicator;

/**
* whether the reply is ready or not
*
*/
bool m_reply_ready;

/**
* reply to be built
*
*/
reply m_reply;
};

} // namespace builders

} // namespace cpp_redis

+ 139
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/reply_builder.hpp Bestand weergeven

@@ -0,0 +1,139 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <deque>
#include <memory>
#include <stdexcept>
#include <string>

#include <cpp_redis/builders/builder_iface.hpp>
#include <cpp_redis/core/reply.hpp>

namespace cpp_redis {

namespace builders {

/**
* class coordinating the several builders and the builder factory to build all the replies returned by redis server
*
*/
class reply_builder {
public:
/**
* ctor
*
*/
reply_builder();
/**
* dtor
*
*/
~reply_builder() = default;

/**
* copy ctor
*
*/
reply_builder(const reply_builder&) = delete;
/**
* assignment operator
*
*/
reply_builder& operator=(const reply_builder&) = delete;

public:
/**
* add data to reply builder
* data is used to build replies that can be retrieved with get_front later on if reply_available returns true
*
* @param data data to be used for building replies
* @return current instance
*
*/
reply_builder& operator<<(const std::string& data);

/**
* similar as get_front, store reply in the passed parameter
*
* @param reply reference to the reply object where to store the first available reply
*
*/
void operator>>(reply& reply);

/**
* @return the first available reply
*
*/
const reply& get_front() const;

/**
* pop the first available reply
*
*/
void pop_front();

/**
* @return whether a reply is available
*
*/
bool reply_available() const;

/**
* reset the reply builder to its initial state (clear internal buffer and stages)
*
*/
void reset();

private:
/**
* build reply using m_buffer content
*
* @return whether the reply has been fully built or not
*
*/
bool build_reply();

private:
/**
* buffer to be used to build data
*
*/
std::string m_buffer;

/**
* current builder used to build current reply
*
*/
std::unique_ptr<builder_iface> m_builder;

/**
* queue of available (built) replies
*
*/
std::deque<reply> m_available_replies;
};

} // namespace builders

} // namespace cpp_redis

+ 113
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/builders/simple_string_builder.hpp Bestand weergeven

@@ -0,0 +1,113 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <string>

#include <cpp_redis/builders/builder_iface.hpp>
#include <cpp_redis/core/reply.hpp>

namespace cpp_redis {

namespace builders {

/**
* builder to build redis simple string replies
*
*/
class simple_string_builder : public builder_iface {
public:
/**
* ctor
*
*/
simple_string_builder();
/**
* dtor
*
*/
~simple_string_builder() override = default;

/**
* copy ctor
*
*/
simple_string_builder(const simple_string_builder&) = delete;
/**
* assignment operator
*
*/
simple_string_builder& operator=(const simple_string_builder&) = delete;

public:
/**
* take data as parameter which is consumed to build the reply
* every bytes used to build the reply must be removed from the buffer passed as parameter
*
* @param data data to be consumed
* @return current instance
*
*/
builder_iface& operator<<(std::string& data) override;

/**
* @return whether the reply could be built
*
*/
bool reply_ready() const override;

/**
* @return reply object
*
*/
reply get_reply() const override;

/**
* @return the parsed simple string
*
*/
const std::string& get_simple_string() const;

private:
/**
* parsed simple string
*
*/
std::string m_str;

/**
* whether the reply is ready or not
*
*/
bool m_reply_ready;

/**
* reply to be built
*
*/
reply m_reply;
};

} // namespace builders

} // namespace cpp_redis

+ 2369
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/client.hpp
Diff onderdrukt omdat het te groot bestand
Bestand weergeven


+ 134
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/consumer.hpp Bestand weergeven

@@ -0,0 +1,134 @@
// The MIT License (MIT)
//
// Copyright (c) 11/27/18 nick. <nbatkins@gmail.com>
//
// 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 CPP_REDIS_CONSUMER_HPP

#ifndef CPP_REDIS_CONSUMER_HPP
#define CPP_REDIS_CONSUMER_HPP

#include <string>
#include <cpp_redis/core/client.hpp>
#include <cpp_redis/misc/dispatch_queue.hpp>

namespace cpp_redis {

using defer = std::shared_ptr<void>;

/**
* reply callback called whenever a reply is received
* takes as parameter the received reply
*/
typedef dispatch_callback_t consumer_callback_t;

typedef client::reply_callback_t reply_callback_t;

typedef struct consumer_callback_container {
consumer_callback_t consumer_callback;
acknowledgement_callback_t acknowledgement_callback;
} consumer_callback_container_t;

typedef struct consumer_reply {
std::string group_id;
xstream_reply_t reply;
} consumer_reply_t;

class consumer_client_container {
public:
consumer_client_container();

client ack_client;
client poll_client;
};

typedef consumer_client_container consumer_client_container_t;

typedef std::unique_ptr<consumer_client_container_t> client_container_ptr_t;

typedef std::multimap<std::string, consumer_callback_container_t> consumer_callbacks_t;

//typedef std::map<std::string, consumer_callback_container_t> consumer_callbacks_t;

class consumer {
public:
explicit consumer(std::string stream, std::string consumer,
size_t max_concurrency = std::thread::hardware_concurrency());

consumer &subscribe(const std::string &group,
const consumer_callback_t &consumer_callback,
const acknowledgement_callback_t &acknowledgement_callback = nullptr);

/**
* @brief Connect to redis server
* @param host host to be connected to
* @param port port to be connected to
* @param connect_callback connect handler to be called on connect events (may be null)
* @param timeout_ms maximum time to connect
* @param max_reconnects maximum attempts of reconnection if connection dropped
* @param reconnect_interval_ms time between two attempts of reconnection
*/
void connect(
const std::string &host = "127.0.0.1",
std::size_t port = 6379,
const connect_callback_t &connect_callback = nullptr,
std::uint32_t timeout_ms = 0,
std::int32_t max_reconnects = 0,
std::uint32_t reconnect_interval_ms = 0);

void auth(const std::string &password,
const reply_callback_t &reply_callback = nullptr);

/*
* commit pipelined transaction
* that is, send to the network all commands pipelined by calling send() / subscribe() / ...
*
* @return current instance
*/
consumer &commit();

void dispatch_changed_handler(size_t size);

private:
void poll();

private:
std::string m_stream;
std::string m_name;
std::string m_read_id;
int m_block_sec;
size_t m_max_concurrency;
int m_read_count;

client_container_ptr_t m_client;

consumer_callbacks_t m_callbacks;
std::mutex m_callbacks_mutex;

dispatch_queue_ptr_t m_dispatch_queue;
std::atomic_bool dispatch_queue_full{false};
std::condition_variable dispatch_queue_changed;
std::mutex dispatch_queue_changed_mutex;

bool is_ready = false;
std::atomic_bool m_should_read_pending{true};
};

} // namespace cpp_redis

#endif //CPP_REDIS_CONSUMER_HPP

+ 288
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/reply.hpp Bestand weergeven

@@ -0,0 +1,288 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <iostream>
#include <string>
#include <vector>

#include <cpp_redis/misc/optional.hpp>

#include <cstdint>

namespace cpp_redis {

/**
* cpp_redis::reply is the class that wraps Redis server replies.
* That is, cpp_redis::reply objects are passed as parameters of commands callbacks and contain the server's response.
*
*/
class reply {
public:
#define __CPP_REDIS_REPLY_ERR 0
#define __CPP_REDIS_REPLY_BULK 1
#define __CPP_REDIS_REPLY_SIMPLE 2
#define __CPP_REDIS_REPLY_NULL 3
#define __CPP_REDIS_REPLY_INT 4
#define __CPP_REDIS_REPLY_ARRAY 5

/**
* type of reply, based on redis server standard replies
*
*/
enum class type {
error = __CPP_REDIS_REPLY_ERR,
bulk_string = __CPP_REDIS_REPLY_BULK,
simple_string = __CPP_REDIS_REPLY_SIMPLE,
null = __CPP_REDIS_REPLY_NULL,
integer = __CPP_REDIS_REPLY_INT,
array = __CPP_REDIS_REPLY_ARRAY
};

/**
* specific type of replies for string-based replies
*
*/
enum class string_type {
error = __CPP_REDIS_REPLY_ERR,
bulk_string = __CPP_REDIS_REPLY_BULK,
simple_string = __CPP_REDIS_REPLY_SIMPLE
};

public:
/**
* default ctor (set a null reply)
*
*/
reply();

/**
* ctor for string values
*
* @param value string value
* @param reply_type of string reply
*
*/
reply(const std::string &value, string_type reply_type);

/**
* ctor for int values
*
* @param value integer value
*
*/
explicit reply(int64_t value);

/**
* ctor for array values
*
* @param rows array reply
* @return current instance
*
*/
explicit reply(const std::vector<reply> &rows);

/**
* dtor
*
*/
~reply() = default;

/**
* copy ctor
*
*/
reply(const reply &) = default;

/**
* assignment operator
*
*/
reply &operator=(const reply &) = default;

/**
* move ctor
*
*/
reply(reply &&) noexcept;

/**
* move assignment operator
*
*/
reply &operator=(reply &&) noexcept;

public:
/**
* @return whether the reply is an array
*
*/
bool is_array() const;

/**
* @return whether the reply is a string (simple, bulk, error)
*
*/
bool is_string() const;

/**
* @return whether the reply is a simple string
*
*/
bool is_simple_string() const;

/**
* @return whether the reply is a bulk string
*
*/
bool is_bulk_string() const;

/**
* @return whether the reply is an error
*
*/
bool is_error() const;

/**
* @return whether the reply is an integer
*
*/
bool is_integer() const;

/**
* @return whether the reply is null
*
*/
bool is_null() const;

public:
/**
* @return true if function is not an error
*
*/
bool ok() const;

/**
* @return true if function is an error
*
*/
bool ko() const;

/**
* convenience implicit conversion, same as !is_null() / ok()
*
*/
explicit operator bool() const;

public:
optional_t<int64_t> try_get_int() const;

public:
/**
* @return the underlying error
*
*/
const std::string &error() const;

/**
* @return the underlying array
*
*/
const std::vector<reply> &as_array() const;

/**
* @return the underlying string
*
*/
const std::string &as_string() const;

/**
* @return the underlying integer
*
*/
int64_t as_integer() const;

public:
/**
* set reply as null
*
*/
void set();

/**
* set a string reply
*
* @param value string value
* @param reply_type of string reply
*
*/
void set(const std::string &value, string_type reply_type);

/**
* set an integer reply
*
* @param value integer value
*
*/
void set(int64_t value);

/**
* set an array reply
*
* @param rows array reply
*
*/
void set(const std::vector<reply> &rows);

/**
* for array replies, add a new row to the reply
*
* @param reply new row to be appended
* @return current instance
*
*/
reply &operator<<(const reply &reply);

public:
/**
* @return reply type
*
*/
type get_type() const;

private:
type m_type;
std::vector<cpp_redis::reply> m_rows;
std::string m_str_val;
int64_t m_int_val;
};

typedef reply reply_t;

} // namespace cpp_redis

/**
* support for output
*
*/
std::ostream &operator<<(std::ostream &os, const cpp_redis::reply_t &reply);

+ 420
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/sentinel.hpp Bestand weergeven

@@ -0,0 +1,420 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <atomic>
#include <condition_variable>
#include <queue>
#include <utility>
#include <vector>

#include <cpp_redis/misc/logger.hpp>
#include <cpp_redis/network/redis_connection.hpp>

namespace cpp_redis {

/**
* cpp_redis::sentinel is the class providing sentinel configuration.
* It is meant to be used for sending sentinel-related commands to the remote server and receiving its replies.
* It is also meant to be used with cpp_redis::client and cpp_redis::subscriber for high availability (automatic failover if reconnection is enabled).
*
*/
class sentinel {
public:
/**
* ctor & dtor
*
*/
#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT

/**
* default ctor
*
*/
sentinel();

#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */

/**
* custom ctor to specify custom tcp_client
*
* @param tcp_client tcp client to be used for network communications
*
*/
explicit sentinel(const std::shared_ptr<network::tcp_client_iface> &tcp_client);

/**
* dtor
*
*/
~sentinel();

/**
* copy ctor
*
*/
sentinel(const sentinel &) = delete;

/**
* assignment operator
*
*/
sentinel &operator=(const sentinel &) = delete;

public:
/**
* callback to be called whenever a reply has been received
*
*/
typedef std::function<void(reply &)> reply_callback_t;

/**
* send the given command
* the command is actually pipelined and only buffered, so nothing is sent to the network
* please call commit() to flush the buffer
*
* @param sentinel_cmd command to be sent
* @param callback callback to be called when reply is received for this command
* @return current instance
*
*/
sentinel &send(const std::vector<std::string> &sentinel_cmd, const reply_callback_t &callback = nullptr);

/**
* commit pipelined transaction
* that is, send to the network all commands pipelined by calling send()
*
* @return current instance
*
*/
sentinel &commit();

/**
* same as commit(), but synchronous
* will block until all pending commands have been sent and that a reply has been received for each of them and all underlying callbacks completed
*
* @return current instance
*
*/
sentinel &sync_commit();

/**
* same as sync_commit, but with a timeout
* will simply block until it completes or timeout expires
*
* @return current instance
*
*/
template<class Rep, class Period>
sentinel &
sync_commit(const std::chrono::duration<Rep, Period> &timeout) {
try_commit();

std::unique_lock<std::mutex> lock_callback(m_callbacks_mutex);
__CPP_REDIS_LOG(debug, "cpp_redis::sentinel waiting for callbacks to complete");
if (!m_sync_condvar.wait_for(lock_callback, timeout, [=] {
return m_callbacks_running == 0 && m_callbacks.empty();
})) {
__CPP_REDIS_LOG(debug, "cpp_redis::sentinel finished waiting for callback");
} else {
__CPP_REDIS_LOG(debug, "cpp_redis::sentinel timed out waiting for callback");
}
return *this;
}

public:
/**
* add a sentinel definition. Required for connect() or get_master_addr_by_name() when autoconnect is enabled.
*
* @param host sentinel host
* @param port sentinel port
* @param timeout_ms maximum time to connect
* @return current instance
*
*/
sentinel &add_sentinel(const std::string &host, std::size_t port, std::uint32_t timeout_ms = 0);

/**
* clear all existing sentinels.
*
*/
void clear_sentinels();

public:
/**
* disconnect from redis server
*
* @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed.
*
*/
void disconnect(bool wait_for_removal = false);

/**
* @return whether we are connected to the redis server or not
*
*/
bool is_connected();

/**
* handlers called whenever disconnection occurred
* function takes the sentinel current instance as parameter
*
*/
typedef std::function<void(sentinel &)> sentinel_disconnect_handler_t;

/**
* Connect to 1st active sentinel we find. Requires add_sentinel() to be called first
* will use timeout set for each added sentinel independently
*
* @param disconnect_handler handler to be called whenever disconnection occurs
*
*/
void connect_sentinel(const sentinel_disconnect_handler_t &disconnect_handler = nullptr);

/**
* Connect to named sentinel
*
* @param host host to be connected to
* @param port port to be connected to
* @param timeout_ms maximum time to connect
* @param disconnect_handler handler to be called whenever disconnection occurs
*
*/
void connect(
const std::string &host,
std::size_t port,
const sentinel_disconnect_handler_t &disconnect_handler = nullptr,
std::uint32_t timeout_ms = 0);

/**
* Used to find the current redis master by asking one or more sentinels. Use high availability.
* Handles connect() and disconnect() automatically when autoconnect=true
* This method is synchronous. No need to call sync_commit() or process a reply callback.
* Call add_sentinel() before using when autoconnect==true
*
* @param name sentinel name
* @param host sentinel host
* @param port sentinel port
* @param autoconnect autoconnect we loop through and connect/disconnect as necessary to sentinels that were added using add_sentinel().
* Otherwise we rely on the call to connect to a sentinel before calling this method.
* @return true if a master was found and fills in host and port output parameters, false otherwise
*/
bool get_master_addr_by_name(
const std::string &name,
std::string &host,
std::size_t &port,
bool autoconnect = true);

public:
sentinel &ckquorum(const std::string &name, const reply_callback_t &reply_callback = nullptr);

sentinel &failover(const std::string &name, const reply_callback_t &reply_callback = nullptr);

sentinel &flushconfig(const reply_callback_t &reply_callback = nullptr);

sentinel &master(const std::string &name, const reply_callback_t &reply_callback = nullptr);

sentinel &masters(const reply_callback_t &reply_callback = nullptr);

sentinel &monitor(const std::string &name, const std::string &ip, std::size_t port, std::size_t quorum,
const reply_callback_t &reply_callback = nullptr);

sentinel &ping(const reply_callback_t &reply_callback = nullptr);

sentinel &remove(const std::string &name, const reply_callback_t &reply_callback = nullptr);

sentinel &reset(const std::string &pattern, const reply_callback_t &reply_callback = nullptr);

sentinel &sentinels(const std::string &name, const reply_callback_t &reply_callback = nullptr);

sentinel &set(const std::string &name, const std::string &option, const std::string &value,
const reply_callback_t &reply_callback = nullptr);

sentinel &slaves(const std::string &name, const reply_callback_t &reply_callback = nullptr);

public:
/**
* store informations related to a sentinel
* typically, host, port and connection timeout
*
*/
class sentinel_def {
public:
/**
* ctor
*
*/
sentinel_def(std::string host, std::size_t port, std::uint32_t timeout_ms)
: m_host(std::move(host)), m_port(port), m_timeout_ms(timeout_ms) {}

/**
* dtor
*
*/
~sentinel_def() = default;

public:
/**
* @return sentinel host
*
*/
const std::string &
get_host() const { return m_host; }

/**
* @return sentinel port
*
*/
size_t
get_port() const { return m_port; }

/**
* @return timeout for sentinel
*
*/
std::uint32_t
get_timeout_ms() const { return m_timeout_ms; }

/**
* set connect timeout for sentinel in ms
* @param timeout_ms new value
*
*/
void
set_timeout_ms(std::uint32_t timeout_ms) { m_timeout_ms = timeout_ms; }

private:
/**
* sentinel host
*
*/
std::string m_host;

/**
* sentinel port
*
*/
std::size_t m_port;

/**
* connect timeout config
*
*/
std::uint32_t m_timeout_ms;
};

public:
/**
* @return sentinels
*
*/
const std::vector<sentinel_def> &get_sentinels() const;

/**
* @return sentinels (non-const version)
*
*/
std::vector<sentinel_def> &get_sentinels();

private:
/**
* redis connection receive handler, triggered whenever a reply has been read by the redis connection
*
* @param connection redis_connection instance
* @param reply parsed reply
*
*/
void connection_receive_handler(network::redis_connection &connection, reply &reply);

/**
* redis_connection disconnection handler, triggered whenever a disconnection occurred
*
* @param connection redis_connection instance
*
*/
void connection_disconnect_handler(network::redis_connection &connection);

/**
* Call the user-defined disconnection handler
*
*/
void call_disconnect_handler();

/**
* reset the queue of pending callbacks
*
*/
void clear_callbacks();

/**
* try to commit the pending pipelined
* if client is disconnected, will throw an exception and clear all pending callbacks (call clear_callbacks())
*
*/
void try_commit();

private:
/**
* A pool of 1 or more sentinels we ask to determine which redis server is the master.
*
*/
std::vector<sentinel_def> m_sentinels;

/**
* tcp client for redis sentinel connection
*
*/
network::redis_connection m_client;

/**
* queue of callback to process
*
*/
std::queue<reply_callback_t> m_callbacks;

/**
* user defined disconnection handler to be called on disconnection
*
*/
sentinel_disconnect_handler_t m_disconnect_handler;

/**
* callbacks thread safety
*
*/
std::mutex m_callbacks_mutex;

/**
* condvar for callbacks updates
*
*/
std::condition_variable m_sync_condvar;

/**
* number of callbacks currently being running
*
*/
std::atomic<unsigned int> m_callbacks_running;
};

} // namespace cpp_redis

+ 523
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/subscriber.hpp Bestand weergeven

@@ -0,0 +1,523 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <atomic>
#include <functional>
#include <map>
#include <mutex>
#include <string>

#include <cpp_redis/core/sentinel.hpp>
#include <cpp_redis/core/types.hpp>
#include <cpp_redis/network/redis_connection.hpp>
#include <cpp_redis/network/tcp_client_iface.hpp>

namespace cpp_redis {

/**
* The cpp_redis::subscriber is meant to be used for PUB/SUB communication with the Redis server.
* Please do not use cpp_redis::client to subscribe to some Redis channels as:
* * the behavior is undefined
* * cpp_redis::client is not meant for that
*
*/
class subscriber {
public:
#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT

/**
* ctor
*
*/
subscriber();

#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */

/**
* custom ctor to specify custom tcp_client
*
* @param tcp_client tcp client to be used for network communications
*
*/
explicit subscriber(const std::shared_ptr<network::tcp_client_iface> &tcp_client);

/**
* dtor
*
*/
~subscriber();

/**
* copy ctor
*
*/
subscriber(const subscriber &) = delete;

/**
* assignment operator
*
*/
subscriber &operator=(const subscriber &) = delete;

public:
/**
* @brief Connect to redis server
* @param host host to be connected to
* @param port port to be connected to
* @param connect_callback connect handler to be called on connect events (may be null)
* @param timeout_ms maximum time to connect
* @param max_reconnects maximum attempts of reconnection if connection dropped
* @param reconnect_interval_ms time between two attempts of reconnection
*
*/
void connect(
const std::string &host = "127.0.0.1",
std::size_t port = 6379,
const connect_callback_t &connect_callback = nullptr,
std::uint32_t timeout_ms = 0,
std::int32_t max_reconnects = 0,
std::uint32_t reconnect_interval_ms = 0);

/**
* @brief Connect to redis server
* @param name sentinel name
* @param connect_callback connect handler to be called on connect events (may be null)
* @param timeout_ms maximum time to connect
* @param max_reconnects maximum attempts of reconnection if connection dropped
* @param reconnect_interval_ms time between two attempts of reconnection
*
*/
void connect(
const std::string &name,
const connect_callback_t &connect_callback = nullptr,
std::uint32_t timeout_ms = 0,
std::int32_t max_reconnects = 0,
std::uint32_t reconnect_interval_ms = 0);

/**
* @brief determines client connectivity
* @return whether we are connected to the redis server
*
*/
bool is_connected() const;

/**
* @brief disconnect from redis server
* @param wait_for_removal when set to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed.
*
*/
void disconnect(bool wait_for_removal = false);

/**
* @brief determines if reconnect is in progress
* @return whether an attempt to reconnect is in progress
*
*/
bool is_reconnecting() const;

/**
* @brief stop any reconnect in progress
*
*/
void cancel_reconnect();

public:
/**
* @brief reply callback called whenever a reply is received, takes as parameter the received reply
*
*/
typedef std::function<void(reply &)> reply_callback_t;

/**
* @brief ability to authenticate on the redis server if necessary
* this method should not be called repeatedly as the storage of reply_callback is NOT thread safe (only one reply callback is stored for the subscriber client)
* calling repeatedly auth() is undefined concerning the execution of the associated callbacks
* @param password password to be used for authentication
* @param reply_callback callback to be called on auth completion (nullable)
* @return current instance
*
*/
subscriber &auth(const std::string &password, const reply_callback_t &reply_callback = nullptr);

/**
* @brief Set the label for the connection on the Redis server via the CLIENT SETNAME command.
* This is useful for monitoring and managing connections on the server side of things.
* @param name - string to label the connection with on the server side
* @param reply_callback callback to be called on auth completion (nullable)
* @return current instance
*
*/
subscriber& client_setname(const std::string& name, const reply_callback_t& reply_callback = nullptr);

/**
* subscribe callback, called whenever a new message is published on a subscribed channel
* takes as parameter the channel and the message
*
*/
typedef std::function<void(const std::string &, const std::string &)> subscribe_callback_t;

/**
* Subscribes to the given channel and:
* * calls acknowledgement_callback once the server has acknowledged about the subscription.
* * calls subscribe_callback each time a message is published on this channel.
* The command is not effectively sent immediately but stored in an internal buffer until commit() is called.
*
* @param channel channel to subscribe
* @param callback callback to be called whenever a message is received for this channel
* @param acknowledgement_callback callback to be called on subscription completion (nullable)
* @return current instance
*/
//!
subscriber &subscribe(const std::string &channel, const subscribe_callback_t &callback,
const acknowledgement_callback_t &acknowledgement_callback = nullptr);

/**
* PSubscribes to the given channel and:
* * calls acknowledgement_callback once the server has acknowledged about the subscription.
* * calls subscribe_callback each time a message is published on this channel.
* The command is not effectively sent immediately but stored in an internal buffer until commit() is called.
*
* @param pattern pattern to psubscribe
* @param callback callback to be called whenever a message is received for this pattern
* @param acknowledgement_callback callback to be called on subscription completion (nullable)
* @return current instance
*/
//!
subscriber &psubscribe(const std::string &pattern, const subscribe_callback_t &callback,
const acknowledgement_callback_t &acknowledgement_callback = nullptr);

/**
* unsubscribe from the given channel
* The command is not effectively sent immediately, but stored inside an internal buffer until commit() is called.
*
* @param channel channel to unsubscribe from
* @return current instance
*
*/
subscriber &unsubscribe(const std::string &channel);

/**
* punsubscribe from the given pattern
* The command is not effectively sent immediately, but stored inside an internal buffer until commit() is called.
*
* @param pattern pattern to punsubscribe from
* @return current instance
*
*/
subscriber &punsubscribe(const std::string &pattern);

/**
* commit pipelined transaction
* that is, send to the network all commands pipelined by calling send() / subscribe() / ...
*
* @return current instance
*
*/
subscriber &commit();

public:
/**
* add a sentinel definition. Required for connect() or get_master_addr_by_name() when autoconnect is enabled.
*
* @param host sentinel host
* @param port sentinel port
* @param timeout_ms maximum time to connect
*
*/
void add_sentinel(const std::string &host, std::size_t port, std::uint32_t timeout_ms = 0);

/**
* retrieve sentinel for current client
*
* @return sentinel associated to current client
*
*/
const sentinel &get_sentinel() const;

/**
* retrieve sentinel for current client
* non-const version
*
* @return sentinel associated to current client
*
*/
sentinel &get_sentinel();

/**
* clear all existing sentinels.
*
*/
void clear_sentinels();

private:
/**
* struct to hold callbacks (sub and ack) for a given channel or pattern
*
*/
struct callback_holder {
subscribe_callback_t subscribe_callback;
acknowledgement_callback_t acknowledgement_callback;
};

private:
/**
* redis connection receive handler, triggered whenever a reply has been read by the redis connection
*
* @param connection redis_connection instance
* @param reply parsed reply
*
*/
void connection_receive_handler(network::redis_connection &connection, reply &reply);

/**
* redis_connection disconnection handler, triggered whenever a disconnection occurred
*
* @param connection redis_connection instance
*
*/
void connection_disconnection_handler(network::redis_connection &connection);

/**
* trigger the ack callback for matching channel/pattern
* check if reply is valid
*
* @param reply received reply
*
*/
void handle_acknowledgement_reply(const std::vector<reply> &reply);

/**
* trigger the sub callback for all matching channels/patterns
* check if reply is valid
*
* @param reply received reply
*
*/
void handle_subscribe_reply(const std::vector<reply> &reply);

/**
* trigger the sub callback for all matching channels/patterns
* check if reply is valid
*
* @param reply received reply
*
*/
void handle_psubscribe_reply(const std::vector<reply> &reply);

/**
* find channel or pattern that is associated to the reply and call its ack callback
*
* @param channel channel or pattern that caused the issuance of this reply
* @param channels list of channels or patterns to be searched for the received channel
* @param channels_mtx channels or patterns mtx to be locked for race condition
* @param nb_chans redis server ack reply
*
*/
void
call_acknowledgement_callback(const std::string &channel, const std::map<std::string, callback_holder> &channels,
std::mutex &channels_mtx, int64_t nb_chans);

private:
/**
* reconnect to the previously connected host
* automatically re authenticate and resubscribe to subscribed channel in case of success
*
*/
void reconnect();

/**
* re authenticate to redis server based on previously used password
*
*/
void re_auth();

/**
* re send CLIENT SETNAME to redis server based on previously used name
*
*/
void re_client_setname(void);

/**
* resubscribe (sub and psub) to previously subscribed channels/patterns
*
*/
void re_subscribe();

/**
* @return whether a reconnection attempt should be performed
*
*/
bool should_reconnect() const;

/**
* sleep between two reconnect attempts if necessary
*
*/
void sleep_before_next_reconnect_attempt();

/**
* clear all subscriptions (dirty way, no unsub/punsub commands send: mostly used for cleaning in disconnection condition)
*
*/
void clear_subscriptions();

private:
/**
* unprotected sub
* same as subscribe, but without any mutex lock
*
* @param channel channel to subscribe
* @param callback callback to be called whenever a message is received for this channel
* @param acknowledgement_callback callback to be called on subscription completion (nullable)
*
*/
void unprotected_subscribe(const std::string &channel, const subscribe_callback_t &callback,
const acknowledgement_callback_t &acknowledgement_callback);

/**
* unprotected psub
* same as psubscribe, but without any mutex lock
*
* @param pattern pattern to psubscribe
* @param callback callback to be called whenever a message is received for this pattern
* @param acknowledgement_callback callback to be called on subscription completion (nullable)
*
*/
void unprotected_psubscribe(const std::string &pattern, const subscribe_callback_t &callback,
const acknowledgement_callback_t &acknowledgement_callback);

private:
/**
* server we are connected to
*
*/
std::string m_redis_server;
/**
* port we are connected to
*
*/
std::size_t m_redis_port = 0;
/**
* master name (if we are using sentinel) we are connected to
*
*/
std::string m_master_name;
/**
* password used to authenticate
*
*/
std::string m_password;

/**
* name to use with CLIENT SETNAME
*
*/
std::string m_client_name;

/**
* tcp client for redis connection
*
*/
network::redis_connection m_client;

/**
* redis sentinel
*
*/
cpp_redis::sentinel m_sentinel;

/**
* max time to connect
*
*/
std::uint32_t m_connect_timeout_ms = 0;
/**
* max number of reconnection attempts
*
*/
std::int32_t m_max_reconnects = 0;
/**
* current number of attempts to reconnect
*
*/
std::int32_t m_current_reconnect_attempts = 0;
/**
* time between two reconnection attempts
*
*/
std::uint32_t m_reconnect_interval_ms = 0;

/**
* reconnection status
*
*/
std::atomic_bool m_reconnecting;
/**
* to force cancel reconnection
*
*/
std::atomic_bool m_cancel;

/**
* subscribed channels and their associated channels
*
*/
std::map<std::string, callback_holder> m_subscribed_channels;
/**
* psubscribed channels and their associated channels
*
*/
std::map<std::string, callback_holder> m_psubscribed_channels;

/**
* connect handler
*
*/
connect_callback_t m_connect_callback;

/**
* sub chans thread safety
*
*/
std::mutex m_psubscribed_channels_mutex;
/**
* psub chans thread safety
*
*/
std::mutex m_subscribed_channels_mutex;

/**
* auth reply callback
*
*/
reply_callback_t m_auth_reply_callback;

/**
* client setname reply callback
*
*/
reply_callback_t m_client_setname_reply_callback;
};

} // namespace cpp_redis

+ 183
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/core/types.hpp Bestand weergeven

@@ -0,0 +1,183 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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 CPP_REDIS_CORE_TYPES_HPP
#define CPP_REDIS_CORE_TYPES_HPP

#include <string>
#include <vector>
#include <map>
#include <ctime>
#include <chrono>
#include <cpp_redis/core/reply.hpp>
#include <functional>
#include <cpp_redis/impl/types.hpp>


namespace cpp_redis {
typedef std::int64_t ms;
/**
* @brief first array is the session name, second is ids
*
*/
typedef std::pair<std::vector<std::string>, std::vector<std::string>> streams_t;

/**
* @brief Options
*/

typedef struct xread_options {
streams_t Streams;
std::int64_t Count;
std::int64_t Block;
} xread_options_t;

typedef struct xreadgroup_options {
std::string Group;
std::string Consumer;
streams_t Streams;
std::int64_t Count;
std::int64_t Block;
bool NoAck;
} xreadgroup_options_t;

typedef struct range_options {
std::string Start;
std::string Stop;
std::int64_t Count;
} range_options_t;

typedef struct xclaim_options {
std::int64_t Idle;
std::time_t *Time;
std::int64_t RetryCount;
bool Force;
bool JustId;
} xclaim_options_t;

typedef struct xpending_options {
range_options_t Range;
std::string Consumer;
} xpending_options_t;

/**
* @brief Replies
*/

class xmessage : public message_type {
public:
xmessage();

explicit xmessage(const reply_t &data);

friend std::ostream &operator<<(std::ostream &os, const xmessage &xm);
};

typedef xmessage xmessage_t;

class xstream {
public:
explicit xstream(const reply_t &data);

friend std::ostream &operator<<(std::ostream &os, const xstream &xs);

std::string Stream;
std::vector<xmessage_t> Messages;
};

typedef xstream xstream_t;

class xinfo_reply {
public:
explicit xinfo_reply(const cpp_redis::reply &data);

std::int64_t Length;
std::int64_t RadixTreeKeys;
std::int64_t RadixTreeNodes;
std::int64_t Groups;
std::string LastGeneratedId;
xmessage_t FirstEntry;
xmessage_t LastEntry;
};

class xstream_reply : public std::vector<xstream_t> {
public:
explicit xstream_reply(const reply_t &data);

friend std::ostream &operator<<(std::ostream &os, const xstream_reply &xs);

bool is_null() const {
if (empty())
return true;
for (auto &v : *this) {
if (v.Messages.empty())
return true;
}
return false;
}
};

typedef xstream_reply xstream_reply_t;

/**
* @brief Callbacks
*/

/**
* acknowledgment callback called whenever a subscribe completes
* takes as parameter the int returned by the redis server (usually the number of channels you are subscribed to)
*
*/
typedef std::function<void(const int64_t &)> acknowledgement_callback_t;

/**
* high availability (re)connection states
* * dropped: connection has dropped
* * start: attempt of connection has started
* * sleeping: sleep between two attempts
* * ok: connected
* * failed: failed to connect
* * lookup failed: failed to retrieve master sentinel
* * stopped: stop to try to reconnect
*
*/
enum class connect_state {
dropped,
start,
sleeping,
ok,
failed,
lookup_failed,
stopped
};

/**
* connect handler, called whenever a new connection even occurred
*
*/
typedef std::function<void(const std::string &host, std::size_t port, connect_state status)> connect_callback_t;

typedef std::function<void(const cpp_redis::message_type&)> message_callback_t;
} // namespace cpp_redis


#endif //CPP_REDIS_TYPES_HPP

+ 42
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/cpp_redis Bestand weergeven

@@ -0,0 +1,42 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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 __CPP_REDIS_
#define __CPP_REDIS_

#ifdef _WIN32
#pragma comment( lib, "ws2_32.lib")
#endif /* _WIN32 */

#include <cpp_redis/core/client.hpp>
#include <cpp_redis/core/consumer.hpp>
#include <cpp_redis/core/subscriber.hpp>
#include <cpp_redis/core/reply.hpp>
#include <cpp_redis/misc/error.hpp>
#include <cpp_redis/misc/logger.hpp>
#include <cpp_redis/core/types.hpp>

#endif

#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT
#include <cpp_redis/network/tcp_client.hpp>
#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */

+ 41
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/generate_rand.hpp Bestand weergeven

@@ -0,0 +1,41 @@
//
// Created by nick on 11/22/18.
//
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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 CPP_REDIS_GENERATE_RAND_HPP
#define CPP_REDIS_GENERATE_RAND_HPP

#include <random>
#include <string>

namespace cpp_redis {
inline std::string generate_rand() {
std::mt19937 rng;
rng.seed(std::random_device()());
std::uniform_int_distribution<std::mt19937::result_type> dist6(1,6); // distribution in range [1, 6]
return std::to_string(dist6(rng));
}
}

#endif //CPP_REDIS_GENERATE_RAND_HPP

+ 130
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/helpers/variadic_template.hpp Bestand weergeven

@@ -0,0 +1,130 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <type_traits>

namespace cpp_redis {
namespace helpers {

/**
* type traits to return last element of a variadic list
*
*/
template <typename T, typename... Args>
struct back {
/**
* last type of variadic list
*
*/
using type = typename back<Args...>::type;
};

/**
* type traits to return last element of a variadic list
*
*/
template <typename T>
struct back<T> {
/**
* templated type
*
*/
using type = T;
};

/**
* type traits to return front element of a variadic list
*
*/
template <typename T, typename... Ts>
struct front {
/**
* front type of variadic list
*
*/
using type = T;
};

/**
* type traits to check if type is present in variadic list
*
*/
template <typename T1, typename T2, typename... Ts>
struct is_type_present {
/**
* true if T1 is present in remaining types of variadic list
* false otherwise
*
*/
static constexpr bool value = std::is_same<T1, T2>::value
? true
: is_type_present<T1, Ts...>::value;
};

/**
* type traits to check if type is present in variadic list
*
*/
template <typename T1, typename T2>
struct is_type_present<T1, T2> {
/**
* true if T1 and T2 are the same
* false otherwise
*
*/
static constexpr bool value = std::is_same<T1, T2>::value;
};

/**
* type traits to check if type is not present in variadic list
*
*/
template <typename T, typename... Args>
struct is_different_types {
/**
* true if T is not in remaining types of variadic list
* false otherwise
*
*/
static constexpr bool value = is_type_present<T, Args...>::value
? false
: is_different_types<Args...>::value;
};

/**
* type traits to check if type is not present in variadic list
*
*/
template <typename T1>
struct is_different_types<T1> {
/**
* true
*
*/
static constexpr bool value = true;
};

} // namespace helpers

} // namespace cpp_redis

+ 131
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/client.ipp Bestand weergeven

@@ -0,0 +1,131 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#include <functional>
#include <iostream>

namespace cpp_redis {

template <typename T>
typename std::enable_if<std::is_same<T, client::client_type>::value>::type
client::client_kill_unpack_arg(std::vector<std::string>& redis_cmd, reply_callback_t&, client_type type) {
redis_cmd.emplace_back("TYPE");
std::string type_string;

switch (type) {
case client_type::normal: type_string = "normal"; break;
case client_type::master: type_string = "master"; break;
case client_type::pubsub: type_string = "pubsub"; break;
case client_type::slave: type_string = "slave"; break;
}

redis_cmd.emplace_back(type_string);
}

template <typename T>
typename std::enable_if<std::is_same<T, bool>::value>::type
client::client_kill_unpack_arg(std::vector<std::string>& redis_cmd, reply_callback_t&, bool skip) {
redis_cmd.emplace_back("SKIPME");
redis_cmd.emplace_back(skip ? "yes" : "no");
}

template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
client::client_kill_unpack_arg(std::vector<std::string>& redis_cmd, reply_callback_t&, uint64_t id) {
redis_cmd.emplace_back("ID");
redis_cmd.emplace_back(std::to_string(id));
}

template <typename T>
typename std::enable_if<std::is_class<T>::value>::type
client::client_kill_unpack_arg(std::vector<std::string>&, reply_callback_t& reply_callback, const T& cb) {
reply_callback = cb;
}

template <typename T, typename... Ts>
void
client::client_kill_impl(std::vector<std::string>& redis_cmd, reply_callback_t& reply, const T& arg, const Ts&... args) {
static_assert(!std::is_class<T>::value, "Reply callback should be in the end of the argument list");
client_kill_unpack_arg<T>(redis_cmd, reply, arg);
client_kill_impl(redis_cmd, reply, args...);
}

template <typename T>
void
client::client_kill_impl(std::vector<std::string>& redis_cmd, reply_callback_t& reply, const T& arg) {
client_kill_unpack_arg<T>(redis_cmd, reply, arg);
}

template <typename T, typename... Ts>
inline client&
client::client_kill(const T& arg, const Ts&... args) {
static_assert(helpers::is_different_types<T, Ts...>::value, "Should only have one distinct value per filter type");
static_assert(!(std::is_class<T>::value && std::is_same<T, typename helpers::back<T, Ts...>::type>::value), "Should have at least one filter");

std::vector<std::string> redis_cmd({"CLIENT", "KILL"});
reply_callback_t reply_cb = nullptr;
client_kill_impl<T, Ts...>(redis_cmd, reply_cb, arg, args...);

return send(redis_cmd, reply_cb);
}

template <typename T, typename... Ts>
inline client&
client::client_kill(const std::string& host, int port, const T& arg, const Ts&... args) {
static_assert(helpers::is_different_types<T, Ts...>::value, "Should only have one distinct value per filter type");
std::vector<std::string> redis_cmd({"CLIENT", "KILL"});

//! If we have other type than lambda, then it's a filter
if (!std::is_class<T>::value) {
redis_cmd.emplace_back("ADDR");
}

redis_cmd.emplace_back(host + ":" + std::to_string(port));
reply_callback_t reply_cb = nullptr;
client_kill_impl<T, Ts...>(redis_cmd, reply_cb, arg, args...);

return send(redis_cmd, reply_cb);
}

inline client&
client::client_kill(const std::string& host, int port) {
return client_kill(host, port, reply_callback_t(nullptr));
}

template <typename... Ts>
inline client&
client::client_kill(const char* host, int port, const Ts&... args) {
return client_kill(std::string(host), port, args...);
}

template <typename T, typename... Ts>
std::future<reply>
client::client_kill_future(const T arg, const Ts... args) {
//! gcc 4.8 doesn't handle variadic template capture arguments (appears in 4.9)
//! so std::bind should capture all arguments because of the compiler.
return exec_cmd(std::bind([this](T arg, Ts... args, const reply_callback_t& cb) -> client& {
return client_kill(arg, args..., cb);
},
arg, args..., std::placeholders::_1));
}

} // namespace cpp_redis

+ 157
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/impl/types.hpp Bestand weergeven

@@ -0,0 +1,157 @@
#include <utility>

// The MIT License (MIT)
//
// Copyright (c) 11/27/18 nick. <nbatkins@gmail.com>
//
// 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 CPP_REDIS_TYPES_HPP
#ifndef CPP_REDIS_IMPL_TYPES_HPP
#define CPP_REDIS_IMPL_TYPES_HPP

#include <cpp_redis/core/reply.hpp>
#include <cpp_redis/misc/convert.hpp>
#include <cpp_redis/misc/logger.hpp>
#include <cpp_redis/misc/optional.hpp>
#include <sstream>
#include <string>
#include <vector>

#include <map>


namespace cpp_redis {

class serializer_type {
public:
inline serializer_type() {}
virtual ~serializer_type() {}

/**
* @return the underlying string
*
*/
virtual const std::string& as_string() const = 0;

/**
* @return the underlying integer
*
*/
virtual optional_t<int64_t> try_get_int() const = 0;

protected:
std::string m_str_val;
};

typedef std::shared_ptr<serializer_type> serializer_ptr_t;

template <typename T>
class message_impl {
public:
virtual ~message_impl() {}

virtual const std::string get_id() const = 0;

virtual const message_impl& set_id(std::string id) = 0;

virtual T find(std::string key) const = 0;

virtual const message_impl& push(std::string key, T value) = 0;

virtual const message_impl& push(std::vector<std::pair<std::string, T>> values) = 0;

virtual const message_impl& push(typename std::vector<T>::const_iterator ptr_begin,
typename std::vector<T>::const_iterator ptr_end) = 0;

virtual const std::multimap<std::string, T>& get_values() const = 0;

protected:
std::string m_id;
std::multimap<std::string, T> m_values;
};

class message_type : public message_impl<reply_t> {
public:
inline const std::string
get_id() const override { return m_id; };

inline const message_type&
set_id(std::string id) override {
m_id = id;
return *this;
}

inline reply_t
find(std::string key) const override {
auto it = m_values.find(key);
if (it != m_values.end())
return it->second;
else
throw "value not found";
};

inline message_type&
push(std::string key, reply_t value) override {
m_values.insert({key, std::move(value)});
return *this;
}

inline message_type&
push(std::vector<std::pair<std::string, reply_t>> values) override {
for (auto& v : values) {
m_values.insert({v.first, std::move(v.second)});
}
return *this;
}

inline message_type&
push(std::vector<reply_t>::const_iterator ptr_begin,
std::vector<reply_t>::const_iterator ptr_end) override {
std::string key;
size_t i = 2;
for (auto pb = ptr_begin; pb != ptr_end; pb++) {
if (i % 2 == 0) {
key = pb->as_string();
}
else {
m_values.insert({key, *pb});
}
}
return *this;
}

inline const std::multimap<std::string, reply_t>&
get_values() const override {
return m_values;
};

inline std::multimap<std::string, std::string>
get_str_values() const {
std::multimap<std::string, std::string> ret;
for (auto& v : m_values) {
std::stringstream s;
s << v.second;
ret.insert({v.first, s.str()});
}
return ret;
};
};
} // namespace cpp_redis

#endif //CPP_REDIS_TYPES_HPP

+ 48
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/convert.hpp Bestand weergeven

@@ -0,0 +1,48 @@
// The MIT License (MIT)
//
// Copyright (c) 11/27/18 nick. <nbatkins@gmail.com>
//
// 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 CPP_REDIS_CONVERT_HPP
#ifndef CPP_REDIS_CONVERT_HPP
#define CPP_REDIS_CONVERT_HPP

#include <sstream>
#include <cpp_redis/misc/optional.hpp>

namespace cpp_redis {

class try_convert {
public:
template <class T>
static enableIf<std::is_convertible<T, std::string>::value, optional_t<int64_t> > to_int(T value) {
try {
std::stringstream stream(value);
int64_t x;
stream >> x;
return optional_t<int64_t>(x);
} catch (std::exception &exc) {
return {};
}
}
};

}


#endif //CPP_REDIS_CONVERT_HPP

+ 10
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/deprecated.hpp Bestand weergeven

@@ -0,0 +1,10 @@
#pragma once

#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED
#endif

+ 91
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/dispatch_queue.hpp Bestand weergeven

@@ -0,0 +1,91 @@
// The MIT License (MIT)
//
// Copyright (c) 11/27/18 nick. <nbatkins@gmail.com>
//
// 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 CPP_REDIS_CONVERT_HPP
//
// Code modified from https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/dispatch.cpp
//

#ifndef CPP_REDIS_DISPATCH_QUEUE_HPP
#define CPP_REDIS_DISPATCH_QUEUE_HPP

#include <thread>
#include <functional>
#include <vector>
#include <cstdint>
#include <cstdio>
#include <queue>
#include <mutex>
#include <string>
#include <condition_variable>

#include <cpp_redis/impl/types.hpp>

namespace cpp_redis {
typedef std::multimap<std::string, std::string> consumer_response_t;

typedef std::function<consumer_response_t(const cpp_redis::message_type&)> dispatch_callback_t;

typedef std::function<void(size_t size)> notify_callback_t;

typedef struct dispatch_callback_collection {
dispatch_callback_t callback;
message_type message;
} dispatch_callback_collection_t;

class dispatch_queue {

public:
explicit dispatch_queue(std::string name, const notify_callback_t &notify_callback, size_t thread_cnt = 1);
~dispatch_queue();

// dispatch and copy
void dispatch(const cpp_redis::message_type& message, const dispatch_callback_t& op);
// dispatch and move
void dispatch(const cpp_redis::message_type& message, dispatch_callback_t&& op);

// Deleted operations
dispatch_queue(const dispatch_queue& rhs) = delete;
dispatch_queue& operator=(const dispatch_queue& rhs) = delete;
dispatch_queue(dispatch_queue&& rhs) = delete;
dispatch_queue& operator=(dispatch_queue&& rhs) = delete;

size_t size();

private:
std::string m_name;
std::mutex m_threads_lock;
mutable std::vector<std::thread> m_threads;
std::mutex m_mq_mutex;
std::queue<dispatch_callback_collection_t> m_mq;
std::condition_variable m_cv;
bool m_quit = false;

notify_callback_t notify_handler;

void dispatch_thread_handler();
};

typedef dispatch_queue dispatch_queue_t;
typedef std::unique_ptr<dispatch_queue> dispatch_queue_ptr_t;
}


#endif //CPP_REDIS_DISPATCH_QUEUE_HPP

+ 56
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/error.hpp Bestand weergeven

@@ -0,0 +1,56 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <stdexcept>
#include <string>

namespace cpp_redis {

/**
* specialized runtime_error used for cpp_redis error
*
*/
class redis_error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
using std::runtime_error::what;

/**
* ctor (string)
*
*/
explicit redis_error(const std::string& err)
: std::runtime_error(err.c_str()) {
}

/**
* ctor(char*)
*
*/
explicit redis_error(const char* err)
: std::runtime_error(err) {
}
};

} // namespace cpp_redis

+ 258
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/logger.hpp Bestand weergeven

@@ -0,0 +1,258 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <memory>
#include <mutex>
#include <string>

namespace cpp_redis {

/**
* logger_iface
* should be inherited by any class intended to be used for logging
*
*/
class logger_iface {
public:
/**
* ctor
*
*/
logger_iface() = default;
/**
* dtor
*
*/
virtual ~logger_iface() = default;

/**
* copy ctor
*
*/
logger_iface(const logger_iface&) = default;
/**
* assignment operator
*
*/
logger_iface& operator=(const logger_iface&) = default;

public:
/**
* debug logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
virtual void debug(const std::string& msg, const std::string& file, std::size_t line) = 0;

/**
* info logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
virtual void info(const std::string& msg, const std::string& file, std::size_t line) = 0;

/**
* warn logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
virtual void warn(const std::string& msg, const std::string& file, std::size_t line) = 0;

/**
* error logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
virtual void error(const std::string& msg, const std::string& file, std::size_t line) = 0;
};

/**
* default logger class provided by the library
*
*/
class logger : public logger_iface {
public:
/**
* log level
*
*/
enum class log_level {
error = 0,
warn = 1,
info = 2,
debug = 3
};

public:
/**
* ctor
*
*/
explicit logger(log_level level = log_level::info);
/**
* dtor
*
*/
~logger() override = default;

/**
* copy ctor
*
*/
logger(const logger&) = default;
/**
* assignment operator
*
*/
logger& operator=(const logger&) = default;

public:
/**
* debug logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void debug(const std::string& msg, const std::string& file, std::size_t line) override;

/**
* info logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void info(const std::string& msg, const std::string& file, std::size_t line) override;

/**
* warn logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void warn(const std::string& msg, const std::string& file, std::size_t line) override;

/**
* error logging
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void error(const std::string& msg, const std::string& file, std::size_t line) override;

private:
/**
* current log level in use
*
*/
log_level m_level;

/**
* mutex used to serialize logs in multi-threaded environment
*
*/
std::mutex m_mutex;
};

/**
* variable containing the current logger
* by default, not set (no logs)
*
*/
extern std::unique_ptr<logger_iface> active_logger;

/**
* debug logging
* convenience function used internally to call the logger
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void debug(const std::string& msg, const std::string& file, std::size_t line);

/**
* info logging
* convenience function used internally to call the logger
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void info(const std::string& msg, const std::string& file, std::size_t line);

/**
* warn logging
* convenience function used internally to call the logger
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void warn(const std::string& msg, const std::string& file, std::size_t line);

/**
* error logging
* convenience function used internally to call the logger
*
* @param msg message to be logged
* @param file file from which the message is coming
* @param line line in the file of the message
*
*/
void error(const std::string& msg, const std::string& file, std::size_t line);

/**
* convenience macro to log with file and line information
*
*/
#ifdef __CPP_REDIS_LOGGING_ENABLED
#define __CPP_REDIS_LOG(level, msg) cpp_redis::level(msg, __FILE__, __LINE__);
#else
#define __CPP_REDIS_LOG(level, msg)
#endif /* __CPP_REDIS_LOGGING_ENABLED */

} // namespace cpp_redis

+ 31
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/macro.hpp Bestand weergeven

@@ -0,0 +1,31 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#if _WIN32
#define __CPP_REDIS_LENGTH(size) static_cast<unsigned int>(size) // for Windows, convert size to `unsigned int`
#else /* _WIN32 */
#define __CPP_REDIS_LENGTH(size) size // for Unix, keep size as `size_t`
#endif /* _WIN32 */

#define __CPP_REDIS_PRINT(...) printf(__VA_ARGS__)

+ 76
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/misc/optional.hpp Bestand weergeven

@@ -0,0 +1,76 @@
// The MIT License (MIT)
//
// Copyright (c) 11/27/18 nick. <nbatkins@gmail.com>
//
// 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 CPP_REDIS_OPTIONAL_HPP
#ifndef CPP_REDIS_OPTIONAL_HPP
#define CPP_REDIS_OPTIONAL_HPP

#include <string>

// Prefer std optional
#if __cplusplus >= 201703L
#include <optional>

namespace cpp_redis {
template <class T>
using optional_t = std::optional<T>;

template <int I, class T>
using enableIf = typename std::enable_if<I, T>::type;
#else

#include <cpp_redis/misc/logger.hpp>

namespace cpp_redis {
template <int I, class T>
using enableIf = typename std::enable_if<I, T>::type;

template <class T>
struct optional {
optional(T value) : m_value(value) {}
// optional<T>&
// operator()(T value) {
// m_value = value;
// return *this;
// }

T m_value;

template <class U>
enableIf<std::is_convertible<U, T>::value, T>
value_or(U&& v) const {
__CPP_REDIS_LOG(1, "value_or(U&& v)\n")
return std::forward<U>(v);
}

template <class F>
auto
value_or(F&& action) const -> decltype(action()) {
return action();
}
};

template <class T>
using optional_t = optional<T>;
#endif

} // namespace cpp_redis

#endif //CPP_REDIS_OPTIONAL_HPP

+ 219
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/redis_connection.hpp Bestand weergeven

@@ -0,0 +1,219 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <vector>

#include <cpp_redis/builders/reply_builder.hpp>
#include <cpp_redis/network/tcp_client_iface.hpp>

#ifndef __CPP_REDIS_READ_SIZE
#define __CPP_REDIS_READ_SIZE 4096
#endif /* __CPP_REDIS_READ_SIZE */

namespace cpp_redis {

namespace network {

/**
* tcp connection wrapper handling redis protocol
*
*/
class redis_connection {
public:
#ifndef __CPP_REDIS_USE_CUSTOM_TCP_CLIENT

/**
* ctor
*
*/
redis_connection();

#endif /* __CPP_REDIS_USE_CUSTOM_TCP_CLIENT */

/**
* ctor allowing to specify custom tcp client (default ctor uses the default tacopie tcp client)
*
* @param tcp_client tcp client to be used for network communications
*
*/
explicit redis_connection(const std::shared_ptr<tcp_client_iface> &tcp_client);

/**
* dtor
*
*/
~redis_connection();

/**
* copy ctor
*
*/
redis_connection(const redis_connection &) = delete;

/**
* assignment operator
*
*/
redis_connection &operator=(const redis_connection &) = delete;

public:
/**
* disconnection handler takes as parameter the instance of the redis_connection
*
*/
typedef std::function<void(redis_connection &)> disconnection_handler_t;

/**
* reply handler takes as parameter the instance of the redis_connection and the built reply
*
*/
typedef std::function<void(redis_connection &, reply &)> reply_callback_t;

/**
* connect to the given host and port, and set both disconnection and reply callbacks
*
* @param host host to be connected to
* @param port port to be connected to
* @param disconnection_handler handler to be called in case of disconnection
* @param reply_callback handler to be called once a reply is ready
* @param timeout_ms max time to connect (in ms)
*
*/
void connect(
const std::string &host = "127.0.0.1",
std::size_t port = 6379,
const disconnection_handler_t &disconnection_handler = nullptr,
const reply_callback_t &reply_callback = nullptr,
std::uint32_t timeout_ms = 0);

/**
* disconnect from redis server
*
* @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed.
*
*/
void disconnect(bool wait_for_removal = false);

/**
* @return whether we are connected to the redis server or not
*
*/
bool is_connected() const;

/**
* send the given command
* the command is actually pipelined and only buffered, so nothing is sent to the network
* please call commit() to flush the buffer
*
* @param redis_cmd command to be sent
* @return current instance
*
*/
redis_connection &send(const std::vector<std::string> &redis_cmd);

/**
* commit pipelined transaction
* that is, send to the network all commands pipelined by calling send()
*
* @return current instance
*
*/
redis_connection &commit();

private:
/**
* tcp_client receive handler
* called by the tcp_client whenever a read has completed
*
* @param result read result
*
*/
void tcp_client_receive_handler(const tcp_client_iface::read_result &result);

/**
* tcp_client disconnection handler
* called by the tcp_client whenever a disconnection occurred
*
*/
void tcp_client_disconnection_handler();

/**
* transform a user command to a redis command using the redis protocol format
* for example, transform {"GET", "HELLO"} to something like "*2\r\n+GET\r\n+HELLO\r\n"
*
*/
std::string build_command(const std::vector<std::string> &redis_cmd);

private:
/**
* simply call the disconnection handler (does nothing if disconnection handler is set to null)
*
*/
void call_disconnection_handler();

private:
/**
* tcp client for redis connection
*
*/
std::shared_ptr<cpp_redis::network::tcp_client_iface> m_client;

/**
* reply callback called whenever a reply has been read
*
*/
reply_callback_t m_reply_callback;

/**
* disconnection handler whenever a disconnection occurred
*
*/
disconnection_handler_t m_disconnection_handler;

/**
* reply builder used to build replies
*
*/
builders::reply_builder m_builder;

/**
* internal buffer used for pipelining (commands are buffered here and flushed to the tcp client when commit is called)
*
*/
std::string m_buffer;

/**
* protect internal buffer against race conditions
*
*/
std::mutex m_buffer_mutex;
};

} // namespace network

} // namespace cpp_redis

+ 128
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client.hpp Bestand weergeven

@@ -0,0 +1,128 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <cpp_redis/misc/error.hpp>
#include <cpp_redis/network/tcp_client_iface.hpp>

#include <tacopie/tacopie>

namespace cpp_redis {

namespace network {

/**
* implementation of the tcp_client_iface based on tacopie networking library
*
*/
class tcp_client : public tcp_client_iface {
public:
/**
* ctor
*
*/
tcp_client() = default;
/**
* dtor
*
*/
~tcp_client() override = default;

public:
/**
* start the tcp client
*
* @param addr host to be connected to
* @param port port to be connected to
* @param timeout_ms max time to connect in ms
*
*/
void connect(const std::string& addr, std::uint32_t port, std::uint32_t timeout_ms) override;

/**
* stop the tcp client
*
* @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed.
*
*/
void disconnect(bool wait_for_removal = false) override;

/**
* @return whether the client is currently connected or not
*
*/
bool is_connected() const override;

/**
* set number of io service workers for the io service monitoring this tcp connection
*
* @param nb_threads number of threads to be assigned
*
*/
void set_nb_workers(std::size_t nb_threads);

public:
/**
* async read operation
*
* @param request information about what should be read and what should be done after completion
*
*/
void async_read(read_request& request) override;

/**
* async write operation
*
* @param request information about what should be written and what should be done after completion
*
*/
void async_write(write_request& request) override;

public:
/**
* set on disconnection handler
*
* @param disconnection_handler handler to be called in case of a disconnection
*
*/
void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler) override;

private:
/**
* tcp client for redis connection
*
*/
tacopie::tcp_client m_client;
};

/**
* set the number of workers to be assigned for the default io service
*
* @param nb_threads the number of threads to be assigned
*
*/
void set_default_nb_workers(std::size_t nb_threads);

} // namespace network

} // namespace cpp_redis

+ 200
- 0
俱乐部/Source/ServerControl/CppRedis/includes/cpp_redis/network/tcp_client_iface.hpp Bestand weergeven

@@ -0,0 +1,200 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <cstdint>
#include <functional>
#include <string>
#include <vector>

namespace cpp_redis {

namespace network {

/**
* interface defining how tcp client should be implemented to be used inside cpp_redis
*
*/
class tcp_client_iface {
public:
/**
* ctor
*
*/
tcp_client_iface() = default;
/**
* dtor
*
*/
virtual ~tcp_client_iface() = default;

public:
/**
* start the tcp client
*
* @param addr host to be connected to
* @param port port to be connected to
* @param timeout_ms max time to connect in ms
*
*/
virtual void connect(const std::string& addr, std::uint32_t port, std::uint32_t timeout_ms = 0) = 0;

/**
* stop the tcp client
*
* @param wait_for_removal when sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed.
*
*/
virtual void disconnect(bool wait_for_removal = false) = 0;

/**
* @return whether the client is currently connected or not
*
*/
virtual bool is_connected() const = 0;

public:
/**
* structure to store read requests result
*
*/
struct read_result {
/**
* whether the operation succeeded or not
*
*/
bool success;

/**
* read bytes
*
*/
std::vector<char> buffer;
};

/**
* structure to store write requests result
*
*/
struct write_result {
/**
* whether the operation succeeded or not
*
*/
bool success;

/**
* number of bytes written
*
*/
std::size_t size;
};

public:
/**
* async read completion callbacks
* function taking read_result as a parameter
*
*/
typedef std::function<void(read_result&)> async_read_callback_t;

/**
* async write completion callbacks
* function taking write_result as a parameter
*
*/
typedef std::function<void(write_result&)> async_write_callback_t;

public:
/**
* structure to store read requests information
*
*/
struct read_request {
/**
* number of bytes to read
*
*/
std::size_t size;

/**
* callback to be called on operation completion
*
*/
async_read_callback_t async_read_callback;
};

/**
* structure to store write requests information
*
*/
struct write_request {
/**
* bytes to write
*
*/
std::vector<char> buffer;

/**
* callback to be called on operation completion
*
*/
async_write_callback_t async_write_callback;
};

public:
/**
* async read operation
*
* @param request information about what should be read and what should be done after completion
*
*/
virtual void async_read(read_request& request) = 0;

/**
* async write operation
*
* @param request information about what should be written and what should be done after completion
*
*/
virtual void async_write(write_request& request) = 0;

public:
/**
* disconnection handler
*
*/
typedef std::function<void()> disconnection_handler_t;

/**
* set on disconnection handler
*
* @param disconnection_handler handler to be called in case of a disconnection
*
*/
virtual void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler) = 0;
};

} // namespace network

} // namespace cpp_redis

+ 265
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/io_service.hpp Bestand weergeven

@@ -0,0 +1,265 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <vector>

#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/select.h>
#endif /* _WIN32 */

#include <tacopie/network/self_pipe.hpp>
#include <tacopie/network/tcp_socket.hpp>
#include <tacopie/utils/thread_pool.hpp>

#ifndef __TACOPIE_IO_SERVICE_NB_WORKERS
#define __TACOPIE_IO_SERVICE_NB_WORKERS 1
#endif /* __TACOPIE_IO_SERVICE_NB_WORKERS */

namespace tacopie {

//!
//! service that operates IO Handling.
//! It polls sockets for input and output, processes read and write operations and calls the appropriate callbacks.
//!
class io_service {
public:
//!
//! ctor
//!
io_service(void);

//! dtor
~io_service(void);

//! copy ctor
io_service(const io_service&) = delete;
//! assignment operator
io_service& operator=(const io_service&) = delete;

public:
//!
//! reset number of io_service workers assigned to this io_service
//! this can be safely called at runtime, even if the io_service is currently running
//! it can be useful if you need to re-adjust the number of workers
//!
//! \param nb_threads number of workers
//!
void set_nb_workers(std::size_t nb_threads);

public:
//! callback handler typedef
//! called on new socket event if register to io_service
typedef std::function<void(fd_t)> event_callback_t;

//!
//! track socket
//! add socket to io_service tracking for read/write operation
//! socket is polled only if read or write callback is defined
//!
//! \param socket socket to be tracked
//! \param rd_callback callback to be executed on read event
//! \param wr_callback callback to be executed on write event
//!
void track(const tcp_socket& socket, const event_callback_t& rd_callback = nullptr, const event_callback_t& wr_callback = nullptr);

//!
//! update the read callback
//! if socket is not tracked yet, track it
//!
//! \param socket socket to be tracked
//! \param event_callback callback to be executed on read event
//!
void set_rd_callback(const tcp_socket& socket, const event_callback_t& event_callback);

//!
//! update the write callback
//! if socket is not tracked yet, track it
//!
//! \param socket socket to be tracked
//! \param event_callback callback to be executed on write event
//!
void set_wr_callback(const tcp_socket& socket, const event_callback_t& event_callback);

//!
//! remove socket from io_service tracking
//! socket is marked for untracking and will effectively be removed asynchronously from tracking once
//! * poll wakes up
//! * no callback are being executed for that socket
//!
//! re-adding track while socket is pending for untrack is fine and will simply cancel the untrack operation
//!
//! \param socket socket to be untracked
//!
void untrack(const tcp_socket& socket);

//!
//! wait until the socket has been effectively removed
//! basically wait until all pending callbacks are executed
//!
//! \param socket socket to wait for
//!
void wait_for_removal(const tcp_socket& socket);

private:
//!
//! struct tracked_socket
//! contains information about what a current socket is tracking
//! * rd_callback: callback to be executed on read availability
//! * is_executing_rd_callback: whether the rd callback is currently being executed or not
//! * wr_callback: callback to be executed on write availability
//! * is_executing_wr_callback: whether the wr callback is currently being executed or not
//! * marked_for_untrack: whether the socket is marked for being untrack (that is, will be untracked whenever all the callback completed their execution)
//!
//!
struct tracked_socket {
//! ctor
tracked_socket(void)
: rd_callback(nullptr)
, wr_callback(nullptr) {}

//! rd event
event_callback_t rd_callback;
std::atomic<bool> is_executing_rd_callback = ATOMIC_VAR_INIT(false);

//! wr event
event_callback_t wr_callback;
std::atomic<bool> is_executing_wr_callback = ATOMIC_VAR_INIT(false);

//! marked for untrack
std::atomic<bool> marked_for_untrack = ATOMIC_VAR_INIT(false);
};

private:
//!
//! poll worker function
//! main loop of the background thread in charge of the io_service in charge of polling fds
//!
void poll(void);

//!
//! init m_poll_fds_info
//! simply initialize m_polled_fds variable based on m_tracked_sockets information
//!
//! \return maximum fd value polled
//!
int init_poll_fds_info(void);

//!
//! process poll detected events
//! called whenever select/poll completed to check read and write availablity
//!
void process_events(void);

//!
//! process read event reported by select/poll for a given socket
//!
//! \param fd fd for which a read event has been reported
//! \param socket tracked_socket associated to the given fd
//!
void process_rd_event(const fd_t& fd, tracked_socket& socket);

//!
//! process write event reported by select/poll for a given socket
//!
//! \param fd fd for which a write event has been reported
//! \param socket tracked_socket associated to the given fd
//!
void process_wr_event(const fd_t& fd, tracked_socket& socket);

private:
//!
//! tracked sockets
//!
std::unordered_map<fd_t, tracked_socket> m_tracked_sockets;

//!
//! whether the worker should stop or not
//!
std::atomic<bool> m_should_stop;

//!
//! poll thread
//!
std::thread m_poll_worker;

//!
//! callback workers
//!
utils::thread_pool m_callback_workers;

//!
//! thread safety
//!
std::mutex m_tracked_sockets_mtx;

//!
//! data structure given to select (list of fds to poll)
//!
std::vector<fd_t> m_polled_fds;

//!
//! data structure given to select (list of fds to poll for read)
//!
fd_set m_rd_set;

//!
//! data structure given to select (list of fds to poll for write)
//!
fd_set m_wr_set;

//!
//! condition variable to wait on removal
//!
std::condition_variable m_wait_for_removal_condvar;

//!
//! fd associated to the pipe used to wake up the poll call
//!
tacopie::self_pipe m_notifier;
};

//!
//! default io_service getter & setter
//!
//! \return shared_ptr to the default instance of the io_service
//!
const std::shared_ptr<io_service>& get_default_io_service(void);

//!
//! set the default io_service to be returned by get_default_io_service
//!
//! \param service the service to be used as the default io_service instance
//!
void set_default_io_service(const std::shared_ptr<io_service>& service);

} // namespace tacopie

+ 90
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/self_pipe.hpp Bestand weergeven

@@ -0,0 +1,90 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <tacopie/utils/typedefs.hpp>

namespace tacopie {

//!
//! used to force poll to wake up
//! simply make poll watch for read events on one side of the pipe and write to the other side
//!
class self_pipe {
public:
//! ctor
self_pipe(void);
//! dtor
~self_pipe(void);

//! copy ctor
self_pipe(const self_pipe&) = delete;
//! assignment operator
self_pipe& operator=(const self_pipe&) = delete;

public:
//!
//! \return the read fd of the pipe
//!
fd_t get_read_fd(void) const;

//!
//! \return the write fd of the pipe
//!
fd_t get_write_fd(void) const;

//!
//! notify the self pipe (basically write to the pipe)
//!
void notify(void);

//!
//! clear the pipe (basically read from the pipe)
//!
void clr_buffer(void);

private:
#ifdef _WIN32
//!
//! socket fd
//!
fd_t m_fd;

//!
//! socket information
//!
struct sockaddr m_addr;

//!
//! socket information (addr len)
//!
int m_addr_len;
#else
//!
//! pipe file descriptors
//!
fd_t m_fds[2];
#endif /* _WIN32 */
};

} // namespace tacopie

+ 330
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_client.hpp Bestand weergeven

@@ -0,0 +1,330 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <atomic>
#include <cstdint>
#include <mutex>
#include <queue>
#include <string>

#include <tacopie/network/io_service.hpp>
#include <tacopie/network/tcp_socket.hpp>
#include <tacopie/utils/typedefs.hpp>

namespace tacopie {

//!
//! tacopie::tcp_server is the class providing TCP Client features.
//! The tcp_client works entirely asynchronously
//!
class tcp_client {
public:
//! ctor & dtor
tcp_client(void);
~tcp_client(void);

//!
//! custom ctor
//! build socket from existing socket
//!
//! \param socket tcp_socket instance to be used for building the client (socket will be moved)
//!
explicit tcp_client(tcp_socket&& socket);

//! copy ctor
tcp_client(const tcp_client&) = delete;
//! assignment operator
tcp_client& operator=(const tcp_client&) = delete;

public:
//!
//! comparison operator
//!
//! \return true when the underlying sockets are the same (same file descriptor and socket type).
//!
bool operator==(const tcp_client& rhs) const;

//!
//! comparison operator
//!
//! \return true when the underlying sockets are different (different file descriptor or socket type).
//!
bool operator!=(const tcp_client& rhs) const;

public:
//!
//! \return the hostname associated with the underlying socket.
//!
const std::string& get_host(void) const;

//!
//! \return the port associated with the underlying socket.
//!
std::uint32_t get_port(void) const;

public:
//!
//! Connect the socket to the remote server.
//!
//! \param host Hostname of the target server
//! \param port Port of the target server
//! \param timeout_msecs maximum time to connect (will block until connect succeed or timeout expire). 0 will block undefinitely. If timeout expires, connection fails
//!
void connect(const std::string& host, std::uint32_t port, std::uint32_t timeout_msecs = 0);

//!
//! Disconnect the tcp_client if it was currently connected.
//!
//! \param wait_for_removal When sets to true, disconnect blocks until the underlying TCP client has been effectively removed from the io_service and that all the underlying callbacks have completed.
//!
void disconnect(bool wait_for_removal = false);

//!
//! \return whether the client is currently connected or not
//!
bool is_connected(void) const;

private:
//!
//! Call the user-defined disconnection handler
//!
void call_disconnection_handler(void);

public:
//!
//! structure to store read requests result
//! * success: Whether the read operation has succeeded or not. If false, the client has been disconnected
//! * buffer: Vector containing the read bytes
//!
struct read_result {
//!
//! whether the operation succeeeded or not
//!
bool success;
//!
//! read bytes
//!
std::vector<char> buffer;
};

//!
//! structure to store write requests result
//! * success: Whether the write operation has succeeded or not. If false, the client has been disconnected
//! * size: Number of bytes written
//!
struct write_result {
//!
//! whether the operation succeeeded or not
//!
bool success;
//!
//! number of bytes written
//!
std::size_t size;
};

public:
//!
//! callback to be called on async read completion
//! takes the read_result as a parameter
//!
typedef std::function<void(read_result&)> async_read_callback_t;

//!
//! callback to be called on async write completion
//! takes the write_result as a parameter
//!
typedef std::function<void(write_result&)> async_write_callback_t;

public:
//!
//! structure to store read requests information
//! * size: Number of bytes to read
//! * async_read_callback: Callback to be called on a read operation completion, even though the operation read less bytes than requested.
//!
struct read_request {
//!
//! number of bytes to read
//!
std::size_t size;
//!
//! callback to be executed on read operation completion
//!
async_read_callback_t async_read_callback;
};

//!
//! structure to store write requests information
//! * buffer: Bytes to be written
//! * async_write_callback: Callback to be called on a write operation completion, even though the operation wrote less bytes than requested.
//!
struct write_request {
//!
//! bytes to write
//!
std::vector<char> buffer;
//!
//! callback to be executed on write operation completion
//!
async_write_callback_t async_write_callback;
};

public:
//!
//! async read operation
//!
//! \param request read request information
//!
void async_read(const read_request& request);

//!
//! async write operation
//!
//! \param request write request information
//!
void async_write(const write_request& request);

public:
//!
//! \return underlying tcp_socket (non-const version)
//!
tacopie::tcp_socket& get_socket(void);

//!
//! \return underlying tcp_socket (const version)
//!
const tacopie::tcp_socket& get_socket(void) const;

public:
//!
//! \return io service monitoring this tcp connection
//!
const std::shared_ptr<tacopie::io_service>& get_io_service(void) const;

public:
//!
//! disconnection handle
//! called whenever a disconnection occured
//!
//!
typedef std::function<void()> disconnection_handler_t;

//!
//! set on disconnection handler
//!
//! \param disconnection_handler the handler to be called on disconnection
//!
void set_on_disconnection_handler(const disconnection_handler_t& disconnection_handler);

private:
//!
//! io service read callback
//! called by the io service whenever the socket is readable
//!
//! \param fd file description of the socket for which the read is available
//!
void on_read_available(fd_t fd);

//!
//! io service write callback
//! called by the io service whenever the socket is writable
//!
//! \param fd file description of the socket for which the write is available
//!
void on_write_available(fd_t fd);

private:
//!
//! Clear pending read requests (basically empty the queue of read requests)
//!
void clear_read_requests(void);

//!
//! Clear pending write requests (basically empty the queue of write requests)
//!
void clear_write_requests(void);

private:
//!
//! process read operations when available
//! basically called whenever on_read_available is called and try to read from the socket
//! handle possible case of failure and fill in the result
//!
//! \param result result of the read operation
//! \return the callback to be executed (set in the read request) on read completion (may be null)
//!
async_read_callback_t process_read(read_result& result);

//!
//! process write operations when available
//! basically called whenever on_write_available is called and try to write to the socket
//! handle possible case of failure and fill in the result
//!
//! \param result result of the write operation
//! \return the callback to be executed (set in the write request) on read completion (may be null)
//!
async_write_callback_t process_write(write_result& result);

private:
//!
//! store io_service
//! prevent deletion of io_service before the tcp_client itself
//!
std::shared_ptr<io_service> m_io_service;

//!
//! client socket
//!
tacopie::tcp_socket m_socket;

//!
//! whether the client is currently connected or not
//!
std::atomic<bool> m_is_connected = ATOMIC_VAR_INIT(false);

//!
//! read requests
//!
std::queue<read_request> m_read_requests;
//!
//! write requests
//!
std::queue<write_request> m_write_requests;

//!
//! read requests thread safety
//!
std::mutex m_read_requests_mtx;
//!
//! write requests thread safety
//!
std::mutex m_write_requests_mtx;

//!
//! disconnection handler
//!
disconnection_handler_t m_disconnection_handler;
};

} // namespace tacopie

+ 175
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_server.hpp Bestand weergeven

@@ -0,0 +1,175 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <atomic>
#include <cstdint>
#include <list>
#include <memory>
#include <mutex>
#include <string>

#include <tacopie/network/io_service.hpp>
#include <tacopie/network/tcp_client.hpp>
#include <tacopie/network/tcp_socket.hpp>
#include <tacopie/utils/typedefs.hpp>

#define __TACOPIE_CONNECTION_QUEUE_SIZE 1024

namespace tacopie {

//!
//! tacopie::tcp_server is the class providing TCP Server features.
//! The tcp_server works entirely asynchronously, waiting for the io_service to notify whenever a new client wished to connect.
//!
class tcp_server {
public:
//! ctor
tcp_server(void);
//! dtor
~tcp_server(void);

//! copy ctor
tcp_server(const tcp_server&) = delete;
//! assignment operator
tcp_server& operator=(const tcp_server&) = delete;

public:
//!
//! comparison operator
//!
//! \return true when the underlying sockets are the same (same file descriptor and socket type).
//!
bool operator==(const tcp_server& rhs) const;

//!
//! comparison operator
//!
//! \return true when the underlying sockets are different (different file descriptor or socket type).
//!
bool operator!=(const tcp_server& rhs) const;

public:
//!
//! callback called whenever a new client is connecting to the server
//!
//! Takes as parameter a shared pointer to the tcp_client that wishes to connect
//! Returning true means connection is handled by tcp_client wrapper and nothing will be done by tcp_server. Returning false means connection is handled by tcp_server, will be stored in an internal list and tcp_client disconection_handler overriden.
//!
typedef std::function<bool(const std::shared_ptr<tcp_client>&)> on_new_connection_callback_t;

//!
//! Start the tcp_server at the given host and port.
//!
//! \param host hostname to be connected to
//! \param port port to be connected to
//! \param callback callback to be called on new connections (may be null, connections are then handled automatically by the tcp_server object)
//!
void start(const std::string& host, std::uint32_t port, const on_new_connection_callback_t& callback = nullptr);

//!
//! Disconnect the tcp_server if it was currently running.
//!
//! \param wait_for_removal When sets to true, disconnect blocks until the underlying TCP server has been effectively removed from the io_service and that all the underlying callbacks have completed.
//! \param recursive_wait_for_removal When sets to true and wait_for_removal is also set to true, blocks until all the underlying TCP client connected to the TCP server have been effectively removed from the io_service and that all the underlying callbacks have completed.
//!
void stop(bool wait_for_removal = false, bool recursive_wait_for_removal = true);

//!
//! \return whether the server is currently running or not
///!
bool is_running(void) const;

public:
//!
//! \return the tacopie::tcp_socket associated to the server. (non-const version)
//!
tcp_socket& get_socket(void);

//!
//! \return the tacopie::tcp_socket associated to the server. (const version)
//!
const tcp_socket& get_socket(void) const;

public:
//!
//! \return io service monitoring this tcp connection
//!
const std::shared_ptr<tacopie::io_service>& get_io_service(void) const;

public:
//!
//! \return the list of tacopie::tcp_client connected to the server.
//!
const std::list<std::shared_ptr<tacopie::tcp_client>>& get_clients(void) const;

private:
//!
//! io service read callback
//!
//! \param fd socket that triggered the read callback
//!
void on_read_available(fd_t fd);

//!
//! client disconnected
//! called whenever a client disconnected from the tcp_server
//!
//! \param client disconnected client
//!
void on_client_disconnected(const std::shared_ptr<tcp_client>& client);

private:
//!
//! store io_service
//! prevent deletion of io_service before the tcp_server itself
//!
std::shared_ptr<io_service> m_io_service;

//1
//! server socket
//!
tacopie::tcp_socket m_socket;

//!
//! whether the server is currently running or not
//!
std::atomic<bool> m_is_running = ATOMIC_VAR_INIT(false);

//!
//! clients
//!
std::list<std::shared_ptr<tacopie::tcp_client>> m_clients;

//!
//! clients thread safety
//!
std::mutex m_clients_mtx;

//!
//! on new connection callback
//!
on_new_connection_callback_t m_on_new_connection_callback;
};

} // namespace tacopie

+ 223
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/network/tcp_socket.hpp Bestand weergeven

@@ -0,0 +1,223 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include <tacopie/utils/typedefs.hpp>

namespace tacopie {

//!
//! tacopie::tcp_socket is the class providing low-level TCP socket features.
//! The tcp_socket provides a simple but convenient abstraction to unix and windows sockets.
//! It also provides a socket type checker to ensure that server-only operations are only processable on server sockets, and client-only operations are only processable on client sockets.
//!
class tcp_socket {
public:
//!
//! possible types of a TCP socket, either a client or a server
//! type is used to prevent the used of client specific operations on a server socket (and vice-versa)
//!
//! UNKNOWN is used when socket type could not be determined for now
//!
enum class type {
CLIENT,
SERVER,
UNKNOWN
};

public:
//! ctor
tcp_socket(void);
//! dtor
~tcp_socket(void) = default;

//!
//! custom ctor
//! build socket from existing file descriptor
//!
//! \param fd fd of the raw socket that will be used to init the tcp_socket object
//! \param host host associated to the socket
//! \param port port associated to the socket
//! \param t type of the socket (client or server)
tcp_socket(fd_t fd, const std::string& host, std::uint32_t port, type t);

//! move ctor
tcp_socket(tcp_socket&&);

//! copy ctor
tcp_socket(const tcp_socket&) = delete;
//! assignment operator
tcp_socket& operator=(const tcp_socket&) = delete;

public:
//!
//! comparison operator
//!
//! \return true when the underlying sockets are the same (same file descriptor and socket type).
//!
bool operator==(const tcp_socket& rhs) const;

//!
//! comparison operator
//!
//! \return true when the underlying sockets are different (different file descriptor or socket type).
//!
bool operator!=(const tcp_socket& rhs) const;

public:
//!
//! Read data synchronously from the underlying socket.
//! The socket must be of type client to process this operation. If the type of the socket is unknown, the socket type will be set to client.
//!
//! \param size_to_read Number of bytes to read (might read less than requested)
//! \return Returns the read bytes
//!
std::vector<char> recv(std::size_t size_to_read);

//!
//! Send data synchronously to the underlying socket.
//! The socket must be of type client to process this operation. If the type of the socket is unknown, the socket type will be set to client.
//!
//! \param data Buffer containing bytes to be written
//! \param size_to_write Number of bytes to send
//! \return Returns the number of bytes that were effectively sent.
//!
std::size_t send(const std::vector<char>& data, std::size_t size_to_write);

//!
//! Connect the socket to the remote server.
//! The socket must be of type client to process this operation. If the type of the socket is unknown, the socket type will be set to client.
//!
//! \param host Hostname of the target server
//! \param port Port of the target server
//! \param timeout_msecs maximum time to connect (will block until connect succeed or timeout expire). 0 will block undefinitely. If timeout expires, connection fails
//!
void connect(const std::string& host, std::uint32_t port, std::uint32_t timeout_msecs = 0);

//!
//! Binds the socket to the given host and port.
//! The socket must be of type server to process this operation. If the type of the socket is unknown, the socket type will be set to server.
//!
//! \param host Hostname to be bind to
//! \param port Port to be bind to
//!
void bind(const std::string& host, std::uint32_t port);

//!
//! Make the socket listen for incoming connections.
//! Socket must be of type server to process this operation. If the type of the socket is unknown, the socket type will be set to server.
//!
//! \param max_connection_queue Size of the queue for incoming connections to be processed by the server
//!
void listen(std::size_t max_connection_queue);

//!
//! Accept a new incoming connection.
//! The socket must be of type server to process this operation. If the type of the socket is unknown, the socket type will be set to server.
//!
//! \return Return the tcp_socket associated to the newly accepted connection.
//!
tcp_socket accept(void);

//!
//! Close the underlying socket.
//!
void close(void);

public:
//!
//! \return the hostname associated with the underlying socket.
//!
const std::string& get_host(void) const;

//!
//! \return the port associated with the underlying socket.
//!
std::uint32_t get_port(void) const;

//!
//! \return the type associated with the underlying socket.
//!
type get_type(void) const;

//!
//! set type, should be used if some operations determining socket type
//! have been done on the behalf of the tcp_socket instance
//!
//! \param t type of the socket
//!
void set_type(type t);

//!
//! direct access to the underlying fd
//!
//! \return underlying socket fd
//!
fd_t get_fd(void) const;

public:
//!
//! \return whether the host is IPV6
//!
bool is_ipv6(void) const;

private:
//!
//! create a new socket if no socket has been initialized yet
//!
void create_socket_if_necessary(void);

//!
//! check whether the current socket has an approriate type for that kind of operation
//! if current type is UNKNOWN, update internal type with given type
//!
//! \param t expected type of our socket to process the operation
//!
void check_or_set_type(type t);

private:
//!
//! fd associated to the socket
//!
fd_t m_fd;

//!
//! socket hostname information
//!
std::string m_host;
//!
//! socket port information
//!
std::uint32_t m_port;

//!
//! type of the socket
//!
type m_type;
};

} // namespace tacopie

+ 40
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/tacopie Bestand weergeven

@@ -0,0 +1,40 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#ifdef _WIN32
#pragma comment( lib, "ws2_32.lib")
#endif /* _WIN32 */

//! utils
#include <tacopie/utils/error.hpp>
#include <tacopie/utils/logger.hpp>
#include <tacopie/utils/typedefs.hpp>

//! network
#include <tacopie/network/io_service.hpp>
#include <tacopie/network/tcp_server.hpp>
#include <tacopie/network/tcp_socket.hpp>

//! utils
#include <tacopie/utils/thread_pool.hpp>

+ 78
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/error.hpp Bestand weergeven

@@ -0,0 +1,78 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <cstdint>
#include <stdexcept>
#include <string>

#include <tacopie/utils/logger.hpp>

namespace tacopie {

//!
//! specialized runtime_error used for tacopie error
//!
class tacopie_error : public std::runtime_error {
public:
//! ctor
tacopie_error(const std::string& what, const std::string& file, std::size_t line);
//! assignment operator
~tacopie_error(void) = default;

//! copy ctor
tacopie_error(const tacopie_error&) = default;
//! assignment operator
tacopie_error& operator=(const tacopie_error&) = default;

public:
//!
//! \return file in which error occured
//!
const std::string& get_file(void) const;

//!
//! \return line at which the error occured
//!
std::size_t get_line(void) const;

private:
//!
//! file location of the error
//!
std::string m_file;

//!
//! line location of the error
//!
std::size_t m_line;
};

} // namespace tacopie

//! macro for convenience
#define __TACOPIE_THROW(level, what) \
{ \
__TACOPIE_LOG(level, (what)); \
throw tacopie::tacopie_error((what), __FILE__, __LINE__); \
}

+ 215
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/logger.hpp Bestand weergeven

@@ -0,0 +1,215 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <memory>
#include <mutex>
#include <string>

namespace tacopie {

//!
//! logger_iface
//! should be inherited by any class intended to be used for logging
//!
class logger_iface {
public:
//! ctor
logger_iface(void) = default;
//! dtor
virtual ~logger_iface(void) = default;

//! copy ctor
logger_iface(const logger_iface&) = default;
//! assignment operator
logger_iface& operator=(const logger_iface&) = default;

public:
//!
//! debug logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
virtual void debug(const std::string& msg, const std::string& file, std::size_t line) = 0;

//!
//! info logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
virtual void info(const std::string& msg, const std::string& file, std::size_t line) = 0;

//!
//! warn logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
virtual void warn(const std::string& msg, const std::string& file, std::size_t line) = 0;

//!
//! error logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
virtual void error(const std::string& msg, const std::string& file, std::size_t line) = 0;
};

//!
//! default logger class provided by the library
//!
class logger : public logger_iface {
public:
//!
//! log level
//!
enum class log_level {
error = 0,
warn = 1,
info = 2,
debug = 3
};

public:
//! ctor
logger(log_level level = log_level::info);
//! dtor
~logger(void) = default;

//! copy ctor
logger(const logger&) = default;
//! assignment operator
logger& operator=(const logger&) = default;

public:
//!
//! debug logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void debug(const std::string& msg, const std::string& file, std::size_t line);

//!
//! info logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void info(const std::string& msg, const std::string& file, std::size_t line);

//!
//! warn logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void warn(const std::string& msg, const std::string& file, std::size_t line);

//!
//! error logging
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void error(const std::string& msg, const std::string& file, std::size_t line);

private:
//!
//! current log level in use
//!
log_level m_level;

//!
//! mutex used to serialize logs in multithreaded environment
//!
std::mutex m_mutex;
};

//!
//! variable containing the current logger
//! by default, not set (no logs)
//!
extern std::unique_ptr<logger_iface> active_logger;

//!
//! debug logging
//! convenience function used internaly to call the logger
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void debug(const std::string& msg, const std::string& file, std::size_t line);

//!
//! info logging
//! convenience function used internaly to call the logger
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void info(const std::string& msg, const std::string& file, std::size_t line);

//!
//! warn logging
//! convenience function used internaly to call the logger
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void warn(const std::string& msg, const std::string& file, std::size_t line);

//!
//! error logging
//! convenience function used internaly to call the logger
//!
//! \param msg message to be logged
//! \param file file from which the message is coming
//! \param line line in the file of the message
//!
void error(const std::string& msg, const std::string& file, std::size_t line);

//!
//! convenience macro to log with file and line information
//!
#ifdef __TACOPIE_LOGGING_ENABLED
#define __TACOPIE_LOG(level, msg) tacopie::level(msg, __FILE__, __LINE__);
#else
#define __TACOPIE_LOG(level, msg)
#endif /* __TACOPIE_LOGGING_ENABLED */

} // namespace tacopie

+ 169
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/thread_pool.hpp Bestand weergeven

@@ -0,0 +1,169 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#include <atomic>
#include <condition_variable>
#include <functional>
#include <list>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

namespace tacopie {

namespace utils {

//!
//! basic thread pool used to push async tasks from the io_service
//!
class thread_pool {
public:
//!
//! ctor
//! created the worker thread that start working immediately
//!
//! \param nb_threads number of threads to start the thread pool
//!
explicit thread_pool(std::size_t nb_threads);

//! dtor
~thread_pool(void);

//! copy ctor
thread_pool(const thread_pool&) = delete;
//! assignment operator
thread_pool& operator=(const thread_pool&) = delete;

public:
//!
//! task typedef
///! simply a callable taking no parameter
//!
typedef std::function<void()> task_t;

//!
//! add tasks to thread pool
//! task is enqueued and will be executed whenever all previously executed tasked have been executed (or are currently being executed)
//!
//! \param task task to be executed by the threadpool
//!
void add_task(const task_t& task);

//!
//! same as add_task
//!
//! \param task task to be executed by the threadpool
//! \return current instance
//!
thread_pool& operator<<(const task_t& task);

//!
//! stop the thread pool and wait for workers completion
//! if some tasks are pending, they won't be executed
//!
void stop(void);

public:
//!
//! \return whether the thread_pool is running or not
//!
bool is_running(void) const;

public:
//!
//! reset the number of threads working in the thread pool
//! this can be safely called at runtime and can be useful if you need to adjust the number of workers
//!
//! this function returns immediately, but change might be applied in the background
//! that is, increasing number of threads will spwan new threads directly from this function (but they may take a while to start)
//! moreover, shrinking the number of threads can only be applied in the background to make sure to not stop some threads in the middle of their task
//!
//! changing number of workers do not affect tasks to be executed and tasks currently being executed
//!
//! \param nb_threads number of threads
//!
void set_nb_threads(std::size_t nb_threads);

private:
//!
//! worker main loop
//!
void run(void);

//!
//! retrieve a new task
//! fetch the first element in the queue, or wait if no task are available
//!
//! \return a pair <stopped, task>
//! pair.first indicated whether the thread has been marked for stop and should return immediately
//! pair.second contains the task to be executed
//!
std::pair<bool, task_t> fetch_task_or_stop(void);

//!
//! \return whether the thread should stop or not
//!
bool should_stop(void) const;

private:
//!
//! threads
//!
std::list<std::thread> m_workers;

//!
//! number of threads allowed
//!
std::atomic<std::size_t> m_max_nb_threads = ATOMIC_VAR_INIT(0);

//!
//! current number of running threads
//!
std::atomic<std::size_t> m_nb_running_threads = ATOMIC_VAR_INIT(0);

//!
//! whether the thread_pool should stop or not
//!
std::atomic<bool> m_should_stop = ATOMIC_VAR_INIT(false);

//!
//! tasks
//!
std::queue<task_t> m_tasks;

//!
//! tasks thread safety
//!
std::mutex m_tasks_mtx;

//!
//! task condvar to sync on tasks changes
//!
std::condition_variable m_tasks_condvar;
};

} // namespace utils

} // namespace tacopie

+ 46
- 0
俱乐部/Source/ServerControl/CppRedis/includes/tacopie/utils/typedefs.hpp Bestand weergeven

@@ -0,0 +1,46 @@
// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// 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.

#pragma once

#ifdef _WIN32
#include <winsock2.h>
#endif /* _WIN32 */

namespace tacopie {

//! file descriptor platform type
#ifdef _WIN32
typedef SOCKET fd_t;
#define __TACOPIE_INVALID_FD INVALID_SOCKET
#else
typedef int fd_t;
#define __TACOPIE_INVALID_FD -1
#endif /* _WIN32 */

//! ssize_t
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif

} //! tacopie

+ 22
- 0
俱乐部/Source/ServerControl/CppRedis/includes/winsock_initializer.h Bestand weergeven

@@ -0,0 +1,22 @@
#pragma once

#ifdef _WIN32
#include <Winsock2.h>
#include <stdexcept>

class winsock_initializer {
public:
winsock_initializer() {
//! Windows network DLL init
WORD version = MAKEWORD(2, 2);
WSADATA data;

if (WSAStartup(version, &data) != 0) {
throw std::runtime_error("WSAStartup() failure");
}
}
~winsock_initializer() { WSACleanup(); }
};
#else
class winsock_initializer {};
#endif /* _WIN32 */

BIN
俱乐部/Source/ServerControl/KernelEngine/Debug_Unicode/vc142.pdb Bestand weergeven


+ 0
- 8
俱乐部/Source/hiredis/.gitignore Bestand weergeven

@@ -1,8 +0,0 @@
/hiredis-test
/examples/hiredis-example*
/*.o
/*.so
/*.dylib
/*.a
/*.pc
*.dSYM

+ 0
- 97
俱乐部/Source/hiredis/.travis.yml Bestand weergeven

@@ -1,97 +0,0 @@
language: c
sudo: false
compiler:
- gcc
- clang

os:
- linux
- osx

branches:
only:
- staging
- trying
- master

before_script:
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi

addons:
apt:
packages:
- libc6-dbg
- libc6-dev
- libc6:i386
- libc6-dev-i386
- libc6-dbg:i386
- gcc-multilib
- g++-multilib
- valgrind

env:
- BITS="32"
- BITS="64"

script:
- EXTRA_CMAKE_OPTS="-DENABLE_EXAMPLES:BOOL=ON -DHIREDIS_SSL:BOOL=ON";
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
if [ "$BITS" == "32" ]; then
CFLAGS="-m32 -Werror";
CXXFLAGS="-m32 -Werror";
LDFLAGS="-m32";
EXTRA_CMAKE_OPTS=;
else
CFLAGS="-Werror";
CXXFLAGS="-Werror";
fi;
else
TEST_PREFIX="valgrind --track-origins=yes --leak-check=full";
if [ "$BITS" == "32" ]; then
CFLAGS="-m32 -Werror";
CXXFLAGS="-m32 -Werror";
LDFLAGS="-m32";
EXTRA_CMAKE_OPTS=;
else
CFLAGS="-Werror";
CXXFLAGS="-Werror";
fi;
fi;
export CFLAGS CXXFLAGS LDFLAGS TEST_PREFIX EXTRA_CMAKE_OPTS
- mkdir build/ && cd build/
- cmake .. ${EXTRA_CMAKE_OPTS}
- make VERBOSE=1
- ctest -V

matrix:
include:
# Windows MinGW cross compile on Linux
- os: linux
dist: xenial
compiler: mingw
addons:
apt:
packages:
- ninja-build
- gcc-mingw-w64-x86-64
- g++-mingw-w64-x86-64
script:
- mkdir build && cd build
- CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_WITH_INSTALL_RPATH=on
- ninja -v

# Windows MSVC 2017
- os: windows
compiler: msvc
env:
- MATRIX_EVAL="CC=cl.exe && CXX=cl.exe"
before_install:
- eval "${MATRIX_EVAL}"
install:
- choco install ninja
script:
- mkdir build && cd build
- cmd.exe /C '"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 &&
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release &&
ninja -v'
- ctest -V

+ 0
- 199
俱乐部/Source/hiredis/CHANGELOG.md Bestand weergeven

@@ -1,199 +0,0 @@
### 1.0.0 (unreleased)

**BREAKING CHANGES**:

* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
protocol errors. This is consistent with the RESP specification. On 32-bit
platforms, the upper bound is lowered to `SIZE_MAX`.

* Change `redisReply.len` to `size_t`, as it denotes the the size of a string

User code should compare this to `size_t` values as well. If it was used to
compare to other values, casting might be necessary or can be removed, if
casting was applied before.

### 0.x.x (unreleased)
**BREAKING CHANGES**:

* Change `redisReply.len` to `size_t`, as it denotes the the size of a string

User code should compare this to `size_t` values as well.
If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before.

* `redisReplyObjectFunctions.createArray` now takes `size_t` for its length parameter.

### 0.14.0 (2018-09-25)

* Make string2ll static to fix conflict with Redis (Tom Lee [c3188b])
* Use -dynamiclib instead of -shared for OSX (Ryan Schmidt [a65537])
* Use string2ll from Redis w/added tests (Michael Grunder [7bef04, 60f622])
* Makefile - OSX compilation fixes (Ryan Schmidt [881fcb, 0e9af8])
* Remove redundant NULL checks (Justin Brewer [54acc8, 58e6b8])
* Fix bulk and multi-bulk length truncation (Justin Brewer [109197])
* Fix SIGSEGV in OpenBSD by checking for NULL before calling freeaddrinfo (Justin Brewer [546d94])
* Several POSIX compatibility fixes (Justin Brewer [bbeab8, 49bbaa, d1c1b6])
* Makefile - Compatibility fixes (Dimitri Vorobiev [3238cf, 12a9d1])
* Makefile - Fix make install on FreeBSD (Zach Shipko [a2ef2b])
* Makefile - don't assume $(INSTALL) is cp (Igor Gnatenko [725a96])
* Separate side-effect causing function from assert and small cleanup (amallia [b46413, 3c3234])
* Don't send negative values to `__redisAsyncCommand` (Frederik Deweerdt [706129])
* Fix leak if setsockopt fails (Frederik Deweerdt [e21c9c])
* Fix libevent leak (zfz [515228])
* Clean up GCC warning (Ichito Nagata [2ec774])
* Keep track of errno in `__redisSetErrorFromErrno()` as snprintf may use it (Jin Qing [25cd88])
* Solaris compilation fix (Donald Whyte [41b07d])
* Reorder linker arguments when building examples (Tustfarm-heart [06eedd])
* Keep track of subscriptions in case of rapid subscribe/unsubscribe (Hyungjin Kim [073dc8, be76c5, d46999])
* libuv use after free fix (Paul Scott [cbb956])
* Properly close socket fd on reconnect attempt (WSL [64d1ec])
* Skip valgrind in OSX tests (Jan-Erik Rediger [9deb78])
* Various updates for Travis testing OSX (Ted Nyman [fa3774, 16a459, bc0ea5])
* Update libevent (Chris Xin [386802])
* Change sds.h for building in C++ projects (Ali Volkan ATLI [f5b32e])
* Use proper format specifier in redisFormatSdsCommandArgv (Paulino Huerta, Jan-Erik Rediger [360a06, 8655a6])
* Better handling of NULL reply in example code (Jan-Erik Rediger [1b8ed3])
* Prevent overflow when formatting an error (Jan-Erik Rediger [0335cb])
* Compatibility fix for strerror_r (Tom Lee [bb1747])
* Properly detect integer parse/overflow errors (Justin Brewer [93421f])
* Adds CI for Windows and cygwin fixes (owent, [6c53d6, 6c3e40])
* Catch a buffer overflow when formatting the error message
* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13
* Fix warnings, when compiled with -Wshadow
* Make hiredis compile in Cygwin on Windows, now CI-tested
* Bulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now
protocol errors. This is consistent with the RESP specification. On 32-bit
platforms, the upper bound is lowered to `SIZE_MAX`.

* Remove backwards compatibility macro's

This removes the following old function aliases, use the new name now:

| Old | New |
| --------------------------- | ---------------------- |
| redisReplyReaderCreate | redisReaderCreate |
| redisReplyReaderCreate | redisReaderCreate |
| redisReplyReaderFree | redisReaderFree |
| redisReplyReaderFeed | redisReaderFeed |
| redisReplyReaderGetReply | redisReaderGetReply |
| redisReplyReaderSetPrivdata | redisReaderSetPrivdata |
| redisReplyReaderGetObject | redisReaderGetObject |
| redisReplyReaderGetError | redisReaderGetError |

* The `DEBUG` variable in the Makefile was renamed to `DEBUG_FLAGS`

Previously it broke some builds for people that had `DEBUG` set to some arbitrary value,
due to debugging other software.
By renaming we avoid unintentional name clashes.

Simply rename `DEBUG` to `DEBUG_FLAGS` in your environment to make it working again.

### 0.13.3 (2015-09-16)

* Revert "Clear `REDIS_CONNECTED` flag when connection is closed".
* Make tests pass on FreeBSD (Thanks, Giacomo Olgeni)


If the `REDIS_CONNECTED` flag is cleared,
the async onDisconnect callback function will never be called.
This causes problems as the disconnect is never reported back to the user.

### 0.13.2 (2015-08-25)

* Prevent crash on pending replies in async code (Thanks, @switch-st)
* Clear `REDIS_CONNECTED` flag when connection is closed (Thanks, Jerry Jacobs)
* Add MacOS X addapter (Thanks, @dizzus)
* Add Qt adapter (Thanks, Pietro Cerutti)
* Add Ivykis adapter (Thanks, Gergely Nagy)

All adapters are provided as is and are only tested where possible.

### 0.13.1 (2015-05-03)

This is a bug fix release.
The new `reconnect` method introduced new struct members, which clashed with pre-defined names in pre-C99 code.
Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects.
Other non-C99 code can now use hiredis as usual again.
Sorry for the inconvenience.

* Fix memory leak in async reply handling (Salvatore Sanfilippo)
* Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa)

### 0.13.0 (2015-04-16)

This release adds a minimal Windows compatibility layer.
The parser, standalone since v0.12.0, can now be compiled on Windows
(and thus used in other client libraries as well)

* Windows compatibility layer for parser code (tzickel)
* Properly escape data printed to PKGCONF file (Dan Skorupski)
* Fix tests when assert() undefined (Keith Bennett, Matt Stancliff)
* Implement a reconnect method for the client context, this changes the structure of `redisContext` (Aaron Bedra)

### 0.12.1 (2015-01-26)

* Fix `make install`: DESTDIR support, install all required files, install PKGCONF in proper location
* Fix `make test` as 32 bit build on 64 bit platform

### 0.12.0 (2015-01-22)

* Add optional KeepAlive support

* Try again on EINTR errors

* Add libuv adapter

* Add IPv6 support

* Remove possibility of multiple close on same fd

* Add ability to bind source address on connect

* Add redisConnectFd() and redisFreeKeepFd()

* Fix getaddrinfo() memory leak

* Free string if it is unused (fixes memory leak)

* Improve redisAppendCommandArgv performance 2.5x

* Add support for SO_REUSEADDR

* Fix redisvFormatCommand format parsing

* Add GLib 2.0 adapter

* Refactor reading code into read.c

* Fix errno error buffers to not clobber errors

* Generate pkgconf during build

* Silence _BSD_SOURCE warnings

* Improve digit counting for multibulk creation


### 0.11.0

* Increase the maximum multi-bulk reply depth to 7.

* Increase the read buffer size from 2k to 16k.

* Use poll(2) instead of select(2) to support large fds (>= 1024).

### 0.10.1

* Makefile overhaul. Important to check out if you override one or more
variables using environment variables or via arguments to the "make" tool.

* Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements
being created by the default reply object functions.

* Issue #43: Don't crash in an asynchronous context when Redis returns an error
reply after the connection has been made (this happens when the maximum
number of connections is reached).

### 0.10.0

* See commit log.


+ 0
- 29
俱乐部/Source/hiredis/COPYING Bestand weergeven

@@ -1,29 +0,0 @@
Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>

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 Redis 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.

+ 0
- 274
俱乐部/Source/hiredis/Makefile Bestand weergeven

@@ -1,274 +0,0 @@
# Hiredis Makefile
# Copyright (C) 2010-2011 Salvatore Sanfilippo <antirez at gmail dot com>
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
# This file is released under the BSD license, see the COPYING file

OBJ=net.o hiredis.o sds.o async.o read.o sockcompat.o alloc.o
SSL_OBJ=ssl.o
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib
ifeq ($(USE_SSL),1)
EXAMPLES+=hiredis-example-ssl hiredis-example-libevent-ssl
endif
TESTS=hiredis-test
LIBNAME=libhiredis
SSL_LIBNAME=libhiredis_ssl
PKGCONFNAME=hiredis.pc
SSL_PKGCONFNAME=hiredis_ssl.pc

HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}')
HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}')
HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}')
HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}')

# Installation related variables and target
PREFIX?=/usr/local
INCLUDE_PATH?=include/hiredis
LIBRARY_PATH?=lib
PKGCONF_PATH?=pkgconfig
INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH)
INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH)
INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH)

# redis-server configuration used for testing
REDIS_PORT=56379
REDIS_SERVER=redis-server
define REDIS_TEST_CONFIG
daemonize yes
pidfile /tmp/hiredis-test-redis.pid
port $(REDIS_PORT)
bind 127.0.0.1
unixsocket /tmp/hiredis-test-redis.sock
endef
export REDIS_TEST_CONFIG

# Fallback to gcc when $CC is not in $PATH.
CC:=$(shell sh -c 'type $${CC%% *} >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
CXX:=$(shell sh -c 'type $${CXX%% *} >/dev/null 2>/dev/null && echo $(CXX) || echo g++')
OPTIMIZATION?=-O3
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -Wno-missing-field-initializers
DEBUG_FLAGS?= -g -ggdb
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CPPFLAGS) $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS)
REAL_LDFLAGS=$(LDFLAGS)

DYLIBSUFFIX=so
STLIBSUFFIX=a
DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
SSL_DYLIBNAME=$(SSL_LIBNAME).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME)
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
SSL_STLIBNAME=$(SSL_LIBNAME).$(STLIBSUFFIX)
STLIB_MAKE_CMD=$(AR) rcs

# Platform-specific overrides
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')

USE_SSL?=0

# This is required for test.c only
ifeq ($(USE_SSL),1)
CFLAGS+=-DHIREDIS_TEST_SSL
endif

ifeq ($(uname_S),Linux)
SSL_LDFLAGS=-lssl -lcrypto
else
OPENSSL_PREFIX?=/usr/local/opt/openssl
CFLAGS+=-I$(OPENSSL_PREFIX)/include
SSL_LDFLAGS+=-L$(OPENSSL_PREFIX)/lib -lssl -lcrypto
endif

ifeq ($(uname_S),SunOS)
REAL_LDFLAGS+= -ldl -lnsl -lsocket
DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
endif
ifeq ($(uname_S),Darwin)
DYLIBSUFFIX=dylib
DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
endif

all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME)
ifeq ($(USE_SSL),1)
all: $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(SSL_PKGCONFNAME)
endif

# Deps (use make dep to generate this)
async.o: async.c fmacros.h alloc.h async.h hiredis.h read.h sds.h net.h dict.c dict.h win32.h async_private.h
dict.o: dict.c fmacros.h alloc.h dict.h
hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h alloc.h net.h async.h win32.h
alloc.o: alloc.c alloc.h
net.o: net.c fmacros.h net.h hiredis.h read.h sds.h alloc.h sockcompat.h win32.h
read.o: read.c fmacros.h read.h sds.h win32.h
sds.o: sds.c sds.h sdsalloc.h
sockcompat.o: sockcompat.c sockcompat.h
ssl.o: ssl.c hiredis.h read.h sds.h alloc.h async.h async_private.h
test.o: test.c fmacros.h hiredis.h read.h sds.h alloc.h net.h

$(DYLIBNAME): $(OBJ)
$(DYLIB_MAKE_CMD) -o $(DYLIBNAME) $(OBJ) $(REAL_LDFLAGS)

$(STLIBNAME): $(OBJ)
$(STLIB_MAKE_CMD) $(STLIBNAME) $(OBJ)

$(SSL_DYLIBNAME): $(SSL_OBJ)
$(DYLIB_MAKE_CMD) -o $(SSL_DYLIBNAME) $(SSL_OBJ) $(REAL_LDFLAGS) $(SSL_LDFLAGS)

$(SSL_STLIBNAME): $(SSL_OBJ)
$(STLIB_MAKE_CMD) $(SSL_STLIBNAME) $(SSL_OBJ)

dynamic: $(DYLIBNAME)
static: $(STLIBNAME)
ifeq ($(USE_SSL),1)
dynamic: $(SSL_DYLIBNAME)
static: $(SSL_STLIBNAME)
endif

# Binaries:
hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS)

hiredis-example-libevent-ssl: examples/example-libevent-ssl.c adapters/libevent.h $(STLIBNAME) $(SSL_STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)

hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -lev $(STLIBNAME) $(REAL_LDFLAGS)

hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME) $(REAL_LDFLAGS)

hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -livykis $(STLIBNAME) $(REAL_LDFLAGS)

hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) $(REAL_LDFLAGS)

hiredis-example-ssl: examples/example-ssl.c $(STLIBNAME) $(SSL_STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(SSL_STLIBNAME) $(REAL_LDFLAGS) $(SSL_LDFLAGS)

ifndef AE_DIR
hiredis-example-ae:
@echo "Please specify AE_DIR (e.g. <redis repository>/src)"
@false
else
hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME)
endif

ifndef LIBUV_DIR
hiredis-example-libuv:
@echo "Please specify LIBUV_DIR (e.g. ../libuv/)"
@false
else
hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) $(REAL_LDFLAGS)
endif

ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),)
hiredis-example-qt:
@echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR"
@false
else
hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME)
$(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \
$(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore
$(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \
$(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore
$(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore
endif

hiredis-example: examples/example.c $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS)

examples: $(EXAMPLES)

TEST_LIBS = $(STLIBNAME)
ifeq ($(USE_SSL),1)
TEST_LIBS += $(SSL_STLIBNAME) -lssl -lcrypto -lpthread
endif
hiredis-test: test.o $(TEST_LIBS)

hiredis-%: %.o $(STLIBNAME)
$(CC) $(REAL_CFLAGS) -o $@ $< $(TEST_LIBS) $(REAL_LDFLAGS)

test: hiredis-test
./hiredis-test

check: hiredis-test
TEST_SSL=$(USE_SSL) ./test.sh

.c.o:
$(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $<

clean:
rm -rf $(DYLIBNAME) $(STLIBNAME) $(SSL_DYLIBNAME) $(SSL_STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov

dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MM *.c

INSTALL?= cp -pPR

$(PKGCONFNAME): hiredis.h
@echo "Generating $@ for pkgconfig..."
@echo prefix=$(PREFIX) > $@
@echo exec_prefix=\$${prefix} >> $@
@echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@
@echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@
@echo >> $@
@echo Name: hiredis >> $@
@echo Description: Minimalistic C client library for Redis. >> $@
@echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@
@echo Libs: -L\$${libdir} -lhiredis >> $@
@echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@

$(SSL_PKGCONFNAME): hiredis.h
@echo "Generating $@ for pkgconfig..."
@echo prefix=$(PREFIX) > $@
@echo exec_prefix=\$${prefix} >> $@
@echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@
@echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@
@echo >> $@
@echo Name: hiredis_ssl >> $@
@echo Description: SSL Support for hiredis. >> $@
@echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@
@echo Requires: hiredis >> $@
@echo Libs: -L\$${libdir} -lhiredis_ssl >> $@
@echo Libs.private: -lssl -lcrypto >> $@

install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH)
$(INSTALL) hiredis.h async.h read.h sds.h alloc.h $(INSTALL_INCLUDE_PATH)
$(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters
$(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME)
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME)
$(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH)
mkdir -p $(INSTALL_PKGCONF_PATH)
$(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH)

32bit:
@echo ""
@echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386"
@echo ""
$(MAKE) CFLAGS="-m32" LDFLAGS="-m32"

32bit-vars:
$(eval CFLAGS=-m32)
$(eval LDFLAGS=-m32)

gprof:
$(MAKE) CFLAGS="-pg" LDFLAGS="-pg"

gcov:
$(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs"

coverage: gcov
make check
mkdir -p tmp/lcov
lcov -d . -c -o tmp/lcov/hiredis.info
genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info

noopt:
$(MAKE) OPTIMIZATION=""

.PHONY: all test check clean dep install 32bit 32bit-vars gprof gcov noopt

+ 0
- 470
俱乐部/Source/hiredis/README.md Bestand weergeven

@@ -1,470 +0,0 @@
[![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis)

**This Readme reflects the latest changed in the master branch. See [v0.13.3](https://github.com/redis/hiredis/tree/v0.13.3) for the Readme and documentation for the latest release.**

# HIREDIS

Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database.

It is minimalistic because it just adds minimal support for the protocol, but
at the same time it uses a high level printf-alike API in order to make it
much higher level than otherwise suggested by its minimal code base and the
lack of explicit bindings for every Redis command.

Apart from supporting sending commands and receiving replies, it comes with
a reply parser that is decoupled from the I/O layer. It
is a stream parser designed for easy reusability, which can for instance be used
in higher level language bindings for efficient reply parsing.

Hiredis only supports the binary-safe Redis protocol, so you can use it with any
Redis version >= 1.2.0.

The library comes with multiple APIs. There is the
*synchronous API*, the *asynchronous API* and the *reply parsing API*.

## Upgrading to `1.0.0`

Version 1.0.0 marks a stable release of hiredis.
It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory.
It also bundles the updated `sds` library, to sync up with upstream and Redis.
For most applications a recompile against the new hiredis should be enough.
For code changes see the [Changelog](CHANGELOG.md).

## Upgrading from `<0.9.0`

Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
code using hiredis should not be a big pain. The key thing to keep in mind when
upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to
the stateless 0.0.1 that only has a file descriptor to work with.

## Synchronous API

To consume the synchronous API, there are only a few function calls that need to be introduced:

```c
redisContext *redisConnect(const char *ip, int port);
void *redisCommand(redisContext *c, const char *format, ...);
void freeReplyObject(void *reply);
```

### Connecting

The function `redisConnect` is used to create a so-called `redisContext`. The
context is where Hiredis holds state for a connection. The `redisContext`
struct has an integer `err` field that is non-zero when the connection is in
an error state. The field `errstr` will contain a string with a description of
the error. More information on errors can be found in the **Errors** section.
After trying to connect to Redis using `redisConnect` you should
check the `err` field to see if establishing the connection was successful:
```c
redisContext *c = redisConnect("127.0.0.1", 6379);
if (c == NULL || c->err) {
if (c) {
printf("Error: %s\n", c->errstr);
// handle error
} else {
printf("Can't allocate redis context\n");
}
}
```

*Note: A `redisContext` is not thread-safe.*

### Sending commands

There are several ways to issue commands to Redis. The first that will be introduced is
`redisCommand`. This function takes a format similar to printf. In the simplest form,
it is used like this:
```c
reply = redisCommand(context, "SET foo bar");
```

The specifier `%s` interpolates a string in the command, and uses `strlen` to
determine the length of the string:
```c
reply = redisCommand(context, "SET foo %s", value);
```
When you need to pass binary safe strings in a command, the `%b` specifier can be
used. Together with a pointer to the string, it requires a `size_t` length argument
of the string:
```c
reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
```
Internally, Hiredis splits the command in different arguments and will
convert it to the protocol used to communicate with Redis.
One or more spaces separates arguments, so you can use the specifiers
anywhere in an argument:
```c
reply = redisCommand(context, "SET key:%s %s", myid, value);
```

### Using replies

The return value of `redisCommand` holds a reply when the command was
successfully executed. When an error occurs, the return value is `NULL` and
the `err` field in the context will be set (see section on **Errors**).
Once an error is returned the context cannot be reused and you should set up
a new connection.

The standard replies that `redisCommand` are of the type `redisReply`. The
`type` field in the `redisReply` should be used to test what kind of reply
was received:

* **`REDIS_REPLY_STATUS`**:
* The command replied with a status reply. The status string can be accessed using `reply->str`.
The length of this string can be accessed using `reply->len`.

* **`REDIS_REPLY_ERROR`**:
* The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`.

* **`REDIS_REPLY_INTEGER`**:
* The command replied with an integer. The integer value can be accessed using the
`reply->integer` field of type `long long`.

* **`REDIS_REPLY_NIL`**:
* The command replied with a **nil** object. There is no data to access.

* **`REDIS_REPLY_STRING`**:
* A bulk (string) reply. The value of the reply can be accessed using `reply->str`.
The length of this string can be accessed using `reply->len`.

* **`REDIS_REPLY_ARRAY`**:
* A multi bulk reply. The number of elements in the multi bulk reply is stored in
`reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well
and can be accessed via `reply->element[..index..]`.
Redis may reply with nested arrays but this is fully supported.

Replies should be freed using the `freeReplyObject()` function.
Note that this function will take care of freeing sub-reply objects
contained in arrays and nested arrays, so there is no need for the user to
free the sub replies (it is actually harmful and will corrupt the memory).

**Important:** the current version of hiredis (0.10.0) frees replies when the
asynchronous API is used. This means you should not call `freeReplyObject` when
you use this API. The reply is cleaned up by hiredis _after_ the callback
returns. This behavior will probably change in future releases, so make sure to
keep an eye on the changelog when upgrading (see issue #39).

### Cleaning up

To disconnect and free the context the following function can be used:
```c
void redisFree(redisContext *c);
```
This function immediately closes the socket and then frees the allocations done in
creating the context.

### Sending commands (cont'd)

Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
It has the following prototype:
```c
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
```
It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the
arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will
use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments
need to be binary safe, the entire array of lengths `argvlen` should be provided.

The return value has the same semantic as `redisCommand`.

### Pipelining

To explain how Hiredis supports pipelining in a blocking connection, there needs to be
understanding of the internal execution flow.

When any of the functions in the `redisCommand` family is called, Hiredis first formats the
command according to the Redis protocol. The formatted command is then put in the output buffer
of the context. This output buffer is dynamic, so it can hold any number of commands.
After the command is put in the output buffer, `redisGetReply` is called. This function has the
following two execution paths:

1. The input buffer is non-empty:
* Try to parse a single reply from the input buffer and return it
* If no reply could be parsed, continue at *2*
2. The input buffer is empty:
* Write the **entire** output buffer to the socket
* Read from the socket until a single reply could be parsed

The function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply
is expected on the socket. To pipeline commands, the only things that needs to be done is
filling up the output buffer. For this cause, two commands can be used that are identical
to the `redisCommand` family, apart from not returning a reply:
```c
void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
```
After calling either function one or more times, `redisGetReply` can be used to receive the
subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where
the latter means an error occurred while reading a reply. Just as with the other commands,
the `err` field in the context can be used to find out what the cause of this error is.

The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and
a single call to `read(2)`):
```c
redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,&reply); // reply for GET
freeReplyObject(reply);
```
This API can also be used to implement a blocking subscriber:
```c
reply = redisCommand(context,"SUBSCRIBE foo");
freeReplyObject(reply);
while(redisGetReply(context,&reply) == REDIS_OK) {
// consume message
freeReplyObject(reply);
}
```
### Errors

When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
returned. The `err` field inside the context will be non-zero and set to one of the
following constants:

* **`REDIS_ERR_IO`**:
There was an I/O error while creating the connection, trying to write
to the socket or read from the socket. If you included `errno.h` in your
application, you can use the global `errno` variable to find out what is
wrong.

* **`REDIS_ERR_EOF`**:
The server closed the connection which resulted in an empty read.

* **`REDIS_ERR_PROTOCOL`**:
There was an error while parsing the protocol.

* **`REDIS_ERR_OTHER`**:
Any other error. Currently, it is only used when a specified hostname to connect
to cannot be resolved.

In every case, the `errstr` field in the context will be set to hold a string representation
of the error.

## Asynchronous API

Hiredis comes with an asynchronous API that works easily with any event library.
Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html)
and [libevent](http://monkey.org/~provos/libevent/).

### Connecting

The function `redisAsyncConnect` can be used to establish a non-blocking connection to
Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field
should be checked after creation to see if there were errors creating the connection.
Because the connection that will be created is non-blocking, the kernel is not able to
instantly return if the specified host and port is able to accept a connection.

*Note: A `redisAsyncContext` is not thread-safe.*

```c
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
printf("Error: %s\n", c->errstr);
// handle error
}
```

The asynchronous context can hold a disconnect callback function that is called when the
connection is disconnected (either because of an error or per user request). This function should
have the following prototype:
```c
void(const redisAsyncContext *c, int status);
```
On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`
field in the context can be accessed to find out the cause of the error.

The context object is always freed after the disconnect callback fired. When a reconnect is needed,
the disconnect callback is a good point to do so.

Setting the disconnect callback can only be done once per context. For subsequent calls it will
return `REDIS_ERR`. The function to set the disconnect callback has the following prototype:
```c
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
```
`ac->data` may be used to pass user data to this callback, the same can be done for redisConnectCallback.
### Sending commands and their callbacks

In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
Therefore, unlike the synchronous API, there is only a single way to send commands.
Because commands are sent to Redis asynchronously, issuing a command requires a callback function
that is called when the reply is received. Reply callbacks should have the following prototype:
```c
void(redisAsyncContext *c, void *reply, void *privdata);
```
The `privdata` argument can be used to curry arbitrary data to the callback from the point where
the command is initially queued for execution.

The functions that can be used to issue commands in an asynchronous context are:
```c
int redisAsyncCommand(
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
const char *format, ...);
int redisAsyncCommandArgv(
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
int argc, const char **argv, const size_t *argvlen);
```
Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command
was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection
is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is
returned on calls to the `redisAsyncCommand` family.

If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback
for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only
valid for the duration of the callback.

All pending callbacks are called with a `NULL` reply when the context encountered an error.

### Disconnecting

An asynchronous connection can be terminated using:
```c
void redisAsyncDisconnect(redisAsyncContext *ac);
```
When this function is called, the connection is **not** immediately terminated. Instead, new
commands are no longer accepted and the connection is only terminated when all pending commands
have been written to the socket, their respective replies have been read and their respective
callbacks have been executed. After this, the disconnection callback is executed with the
`REDIS_OK` status and the context object is freed.

### Hooking it up to event library *X*

There are a few hooks that need to be set on the context object after it is created.
See the `adapters/` directory for bindings to *libev* and *libevent*.

## Reply parsing API

Hiredis comes with a reply parsing API that makes it easy for writing higher
level language bindings.

The reply parsing API consists of the following functions:
```c
redisReader *redisReaderCreate(void);
void redisReaderFree(redisReader *reader);
int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
int redisReaderGetReply(redisReader *reader, void **reply);
```
The same set of functions are used internally by hiredis when creating a
normal Redis context, the above API just exposes it to the user for a direct
usage.

### Usage

The function `redisReaderCreate` creates a `redisReader` structure that holds a
buffer with unparsed data and state for the protocol parser.

Incoming data -- most likely from a socket -- can be placed in the internal
buffer of the `redisReader` using `redisReaderFeed`. This function will make a
copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed
when `redisReaderGetReply` is called. This function returns an integer status
and a reply object (as described above) via `void **reply`. The returned status
can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went
wrong (either a protocol error, or an out of memory error).

The parser limits the level of nesting for multi bulk payloads to 7. If the
multi bulk nesting level is higher than this, the parser returns an error.

### Customizing replies

The function `redisReaderGetReply` creates `redisReply` and makes the function
argument `reply` point to the created `redisReply` variable. For instance, if
the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply`
will hold the status as a vanilla C string. However, the functions that are
responsible for creating instances of the `redisReply` can be customized by
setting the `fn` field on the `redisReader` struct. This should be done
immediately after creating the `redisReader`.

For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c)
uses customized reply object functions to create Ruby objects.

### Reader max buffer

Both when using the Reader API directly or when using it indirectly via a
normal Redis context, the redisReader structure uses a buffer in order to
accumulate data from the server.
Usually this buffer is destroyed when it is empty and is larger than 16
KiB in order to avoid wasting memory in unused buffers

However when working with very big payloads destroying the buffer may slow
down performances considerably, so it is possible to modify the max size of
an idle buffer changing the value of the `maxbuf` field of the reader structure
to the desired value. The special value of 0 means that there is no maximum
value for an idle buffer, so the buffer will never get freed.

For instance if you have a normal Redis context you can set the maximum idle
buffer to zero (unlimited) just with:
```c
context->reader->maxbuf = 0;
```
This should be done only in order to maximize performances when working with
large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
as soon as possible in order to prevent allocation of useless memory.

## SSL/TLS Support

### Building

SSL/TLS support is not built by default and requires an explicit flag:

make USE_SSL=1

This requires OpenSSL development package (e.g. including header files to be
available.

When enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and
`libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries
unaffected so no additional dependencies are introduced.

### Using it

First, you'll need to make sure you include the SSL header file:

```c
#include "hiredis.h"
#include "hiredis_ssl.h"
```

SSL can only be enabled on a `redisContext` connection after the connection has
been established and before any command has been processed. For example:

```c
c = redisConnect('localhost', 6443);
if (c == NULL || c->err) {
/* Handle error and abort... */
}

if (redisSecureConnection(c,
"cacertbundle.crt", /* File name of trusted CA/ca bundle file */
"client_cert.pem", /* File name of client certificate file */
"client_key.pem", /* File name of client privat ekey */
"redis.mydomain.com" /* Server name to request (SNI) */
) != REDIS_OK) {
printf("SSL error: %s\n", c->errstr);
/* Abort... */
}
```

You will also need to link against `libhiredis_ssl`, **in addition** to
`libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies.

### OpenSSL Global State Initialization

OpenSSL needs to have certain global state initialized before it can be used.
Using `redisSecureConnection()` will handle this automatically on the first
call.

**If the calling application itself also initializes and uses OpenSSL directly,
`redisSecureConnection()` must not be used.**

Instead, use `redisInitiateSSL()` which also provides greater control over the
configuration of the SSL connection, as the caller is responsible to create a
connection context using `SSL_new()` and configure it as required.

## AUTHORS

Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.

+ 0
- 127
俱乐部/Source/hiredis/adapters/ae.h Bestand weergeven

@@ -1,127 +0,0 @@
/*
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/

#ifndef __HIREDIS_AE_H__
#define __HIREDIS_AE_H__
#include <sys/types.h>
#include <ae.h>
#include "../hiredis.h"
#include "../async.h"

typedef struct redisAeEvents {
redisAsyncContext *context;
aeEventLoop *loop;
int fd;
int reading, writing;
} redisAeEvents;

static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
((void)el); ((void)fd); ((void)mask);

redisAeEvents *e = (redisAeEvents*)privdata;
redisAsyncHandleRead(e->context);
}

static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
((void)el); ((void)fd); ((void)mask);

redisAeEvents *e = (redisAeEvents*)privdata;
redisAsyncHandleWrite(e->context);
}

static void redisAeAddRead(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (!e->reading) {
e->reading = 1;
aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e);
}
}

static void redisAeDelRead(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (e->reading) {
e->reading = 0;
aeDeleteFileEvent(loop,e->fd,AE_READABLE);
}
}

static void redisAeAddWrite(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (!e->writing) {
e->writing = 1;
aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e);
}
}

static void redisAeDelWrite(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (e->writing) {
e->writing = 0;
aeDeleteFileEvent(loop,e->fd,AE_WRITABLE);
}
}

static void redisAeCleanup(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
redisAeDelRead(privdata);
redisAeDelWrite(privdata);
free(e);
}

static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisAeEvents *e;

/* Nothing should be attached when something is already attached */
if (ac->ev.data != NULL)
return REDIS_ERR;

/* Create container for context and r/w events */
e = (redisAeEvents*)hi_malloc(sizeof(*e));
e->context = ac;
e->loop = loop;
e->fd = c->fd;
e->reading = e->writing = 0;

/* Register functions to start/stop listening for events */
ac->ev.addRead = redisAeAddRead;
ac->ev.delRead = redisAeDelRead;
ac->ev.addWrite = redisAeAddWrite;
ac->ev.delWrite = redisAeDelWrite;
ac->ev.cleanup = redisAeCleanup;
ac->ev.data = e;

return REDIS_OK;
}
#endif

+ 0
- 153
俱乐部/Source/hiredis/adapters/glib.h Bestand weergeven

@@ -1,153 +0,0 @@
#ifndef __HIREDIS_GLIB_H__
#define __HIREDIS_GLIB_H__

#include <glib.h>

#include "../hiredis.h"
#include "../async.h"

typedef struct
{
GSource source;
redisAsyncContext *ac;
GPollFD poll_fd;
} RedisSource;

static void
redis_source_add_read (gpointer data)
{
RedisSource *source = (RedisSource *)data;
g_return_if_fail(source);
source->poll_fd.events |= G_IO_IN;
g_main_context_wakeup(g_source_get_context((GSource *)data));
}

static void
redis_source_del_read (gpointer data)
{
RedisSource *source = (RedisSource *)data;
g_return_if_fail(source);
source->poll_fd.events &= ~G_IO_IN;
g_main_context_wakeup(g_source_get_context((GSource *)data));
}

static void
redis_source_add_write (gpointer data)
{
RedisSource *source = (RedisSource *)data;
g_return_if_fail(source);
source->poll_fd.events |= G_IO_OUT;
g_main_context_wakeup(g_source_get_context((GSource *)data));
}

static void
redis_source_del_write (gpointer data)
{
RedisSource *source = (RedisSource *)data;
g_return_if_fail(source);
source->poll_fd.events &= ~G_IO_OUT;
g_main_context_wakeup(g_source_get_context((GSource *)data));
}

static void
redis_source_cleanup (gpointer data)
{
RedisSource *source = (RedisSource *)data;

g_return_if_fail(source);

redis_source_del_read(source);
redis_source_del_write(source);
/*
* It is not our responsibility to remove ourself from the
* current main loop. However, we will remove the GPollFD.
*/
if (source->poll_fd.fd >= 0) {
g_source_remove_poll((GSource *)data, &source->poll_fd);
source->poll_fd.fd = -1;
}
}

static gboolean
redis_source_prepare (GSource *source,
gint *timeout_)
{
RedisSource *redis = (RedisSource *)source;
*timeout_ = -1;
return !!(redis->poll_fd.events & redis->poll_fd.revents);
}

static gboolean
redis_source_check (GSource *source)
{
RedisSource *redis = (RedisSource *)source;
return !!(redis->poll_fd.events & redis->poll_fd.revents);
}

static gboolean
redis_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
RedisSource *redis = (RedisSource *)source;

if ((redis->poll_fd.revents & G_IO_OUT)) {
redisAsyncHandleWrite(redis->ac);
redis->poll_fd.revents &= ~G_IO_OUT;
}

if ((redis->poll_fd.revents & G_IO_IN)) {
redisAsyncHandleRead(redis->ac);
redis->poll_fd.revents &= ~G_IO_IN;
}

if (callback) {
return callback(user_data);
}

return TRUE;
}

static void
redis_source_finalize (GSource *source)
{
RedisSource *redis = (RedisSource *)source;

if (redis->poll_fd.fd >= 0) {
g_source_remove_poll(source, &redis->poll_fd);
redis->poll_fd.fd = -1;
}
}

static GSource *
redis_source_new (redisAsyncContext *ac)
{
static GSourceFuncs source_funcs = {
.prepare = redis_source_prepare,
.check = redis_source_check,
.dispatch = redis_source_dispatch,
.finalize = redis_source_finalize,
};
redisContext *c = &ac->c;
RedisSource *source;

g_return_val_if_fail(ac != NULL, NULL);

source = (RedisSource *)g_source_new(&source_funcs, sizeof *source);
source->ac = ac;
source->poll_fd.fd = c->fd;
source->poll_fd.events = 0;
source->poll_fd.revents = 0;
g_source_add_poll((GSource *)source, &source->poll_fd);

ac->ev.addRead = redis_source_add_read;
ac->ev.delRead = redis_source_del_read;
ac->ev.addWrite = redis_source_add_write;
ac->ev.delWrite = redis_source_del_write;
ac->ev.cleanup = redis_source_cleanup;
ac->ev.data = source;

return (GSource *)source;
}

#endif /* __HIREDIS_GLIB_H__ */

+ 0
- 81
俱乐部/Source/hiredis/adapters/ivykis.h Bestand weergeven

@@ -1,81 +0,0 @@
#ifndef __HIREDIS_IVYKIS_H__
#define __HIREDIS_IVYKIS_H__
#include <iv.h>
#include "../hiredis.h"
#include "../async.h"

typedef struct redisIvykisEvents {
redisAsyncContext *context;
struct iv_fd fd;
} redisIvykisEvents;

static void redisIvykisReadEvent(void *arg) {
redisAsyncContext *context = (redisAsyncContext *)arg;
redisAsyncHandleRead(context);
}

static void redisIvykisWriteEvent(void *arg) {
redisAsyncContext *context = (redisAsyncContext *)arg;
redisAsyncHandleWrite(context);
}

static void redisIvykisAddRead(void *privdata) {
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent);
}

static void redisIvykisDelRead(void *privdata) {
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
iv_fd_set_handler_in(&e->fd, NULL);
}

static void redisIvykisAddWrite(void *privdata) {
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent);
}

static void redisIvykisDelWrite(void *privdata) {
redisIvykisEvents *e = (redisIvykisEvents*)privdata;
iv_fd_set_handler_out(&e->fd, NULL);
}

static void redisIvykisCleanup(void *privdata) {
redisIvykisEvents *e = (redisIvykisEvents*)privdata;

iv_fd_unregister(&e->fd);
free(e);
}

static int redisIvykisAttach(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisIvykisEvents *e;

/* Nothing should be attached when something is already attached */
if (ac->ev.data != NULL)
return REDIS_ERR;

/* Create container for context and r/w events */
e = (redisIvykisEvents*)hi_malloc(sizeof(*e));
e->context = ac;

/* Register functions to start/stop listening for events */
ac->ev.addRead = redisIvykisAddRead;
ac->ev.delRead = redisIvykisDelRead;
ac->ev.addWrite = redisIvykisAddWrite;
ac->ev.delWrite = redisIvykisDelWrite;
ac->ev.cleanup = redisIvykisCleanup;
ac->ev.data = e;

/* Initialize and install read/write events */
IV_FD_INIT(&e->fd);
e->fd.fd = c->fd;
e->fd.handler_in = redisIvykisReadEvent;
e->fd.handler_out = redisIvykisWriteEvent;
e->fd.handler_err = NULL;
e->fd.cookie = e->context;

iv_fd_register(&e->fd);

return REDIS_OK;
}
#endif

+ 0
- 147
俱乐部/Source/hiredis/adapters/libev.h Bestand weergeven

@@ -1,147 +0,0 @@
/*
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/

#ifndef __HIREDIS_LIBEV_H__
#define __HIREDIS_LIBEV_H__
#include <stdlib.h>
#include <sys/types.h>
#include <ev.h>
#include "../hiredis.h"
#include "../async.h"

typedef struct redisLibevEvents {
redisAsyncContext *context;
struct ev_loop *loop;
int reading, writing;
ev_io rev, wev;
} redisLibevEvents;

static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
#if EV_MULTIPLICITY
((void)loop);
#endif
((void)revents);

redisLibevEvents *e = (redisLibevEvents*)watcher->data;
redisAsyncHandleRead(e->context);
}

static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
#if EV_MULTIPLICITY
((void)loop);
#endif
((void)revents);

redisLibevEvents *e = (redisLibevEvents*)watcher->data;
redisAsyncHandleWrite(e->context);
}

static void redisLibevAddRead(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (!e->reading) {
e->reading = 1;
ev_io_start(EV_A_ &e->rev);
}
}

static void redisLibevDelRead(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (e->reading) {
e->reading = 0;
ev_io_stop(EV_A_ &e->rev);
}
}

static void redisLibevAddWrite(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (!e->writing) {
e->writing = 1;
ev_io_start(EV_A_ &e->wev);
}
}

static void redisLibevDelWrite(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (e->writing) {
e->writing = 0;
ev_io_stop(EV_A_ &e->wev);
}
}

static void redisLibevCleanup(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
redisLibevDelRead(privdata);
redisLibevDelWrite(privdata);
free(e);
}

static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisLibevEvents *e;

/* Nothing should be attached when something is already attached */
if (ac->ev.data != NULL)
return REDIS_ERR;

/* Create container for context and r/w events */
e = (redisLibevEvents*)hi_malloc(sizeof(*e));
e->context = ac;
#if EV_MULTIPLICITY
e->loop = loop;
#else
e->loop = NULL;
#endif
e->reading = e->writing = 0;
e->rev.data = e;
e->wev.data = e;

/* Register functions to start/stop listening for events */
ac->ev.addRead = redisLibevAddRead;
ac->ev.delRead = redisLibevDelRead;
ac->ev.addWrite = redisLibevAddWrite;
ac->ev.delWrite = redisLibevDelWrite;
ac->ev.cleanup = redisLibevCleanup;
ac->ev.data = e;

/* Initialize read/write events */
ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ);
ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE);
return REDIS_OK;
}

#endif

+ 0
- 172
俱乐部/Source/hiredis/adapters/libevent.h Bestand weergeven

@@ -1,172 +0,0 @@
/*
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/

#ifndef __HIREDIS_LIBEVENT_H__
#define __HIREDIS_LIBEVENT_H__
#include <event2/event.h>
#include "../hiredis.h"
#include "../async.h"

#define REDIS_LIBEVENT_DELETED 0x01
#define REDIS_LIBEVENT_ENTERED 0x02

typedef struct redisLibeventEvents {
redisAsyncContext *context;
struct event *ev;
struct event_base *base;
struct timeval tv;
short flags;
short state;
} redisLibeventEvents;

static void redisLibeventDestroy(redisLibeventEvents *e) {
free(e);
}

static void redisLibeventHandler(int fd, short event, void *arg) {
((void)fd);
redisLibeventEvents *e = (redisLibeventEvents*)arg;
e->state |= REDIS_LIBEVENT_ENTERED;

#define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\
redisLibeventDestroy(e);\
return; \
}

if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
redisAsyncHandleTimeout(e->context);
CHECK_DELETED();
}

if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
redisAsyncHandleRead(e->context);
CHECK_DELETED();
}

if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
redisAsyncHandleWrite(e->context);
CHECK_DELETED();
}

e->state &= ~REDIS_LIBEVENT_ENTERED;
#undef CHECK_DELETED
}

static void redisLibeventUpdate(void *privdata, short flag, int isRemove) {
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL;

if (isRemove) {
if ((e->flags & flag) == 0) {
return;
} else {
e->flags &= ~flag;
}
} else {
if (e->flags & flag) {
return;
} else {
e->flags |= flag;
}
}

event_del(e->ev);
event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST,
redisLibeventHandler, privdata);
event_add(e->ev, tv);
}

static void redisLibeventAddRead(void *privdata) {
redisLibeventUpdate(privdata, EV_READ, 0);
}

static void redisLibeventDelRead(void *privdata) {
redisLibeventUpdate(privdata, EV_READ, 1);
}

static void redisLibeventAddWrite(void *privdata) {
redisLibeventUpdate(privdata, EV_WRITE, 0);
}

static void redisLibeventDelWrite(void *privdata) {
redisLibeventUpdate(privdata, EV_WRITE, 1);
}

static void redisLibeventCleanup(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
if (!e) {
return;
}
event_del(e->ev);
event_free(e->ev);
e->ev = NULL;

if (e->state & REDIS_LIBEVENT_ENTERED) {
e->state |= REDIS_LIBEVENT_DELETED;
} else {
redisLibeventDestroy(e);
}
}

static void redisLibeventSetTimeout(void *privdata, struct timeval tv) {
redisLibeventEvents *e = (redisLibeventEvents *)privdata;
short flags = e->flags;
e->flags = 0;
e->tv = tv;
redisLibeventUpdate(e, flags, 0);
}

static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
redisContext *c = &(ac->c);
redisLibeventEvents *e;

/* Nothing should be attached when something is already attached */
if (ac->ev.data != NULL)
return REDIS_ERR;

/* Create container for context and r/w events */
e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e));
e->context = ac;

/* Register functions to start/stop listening for events */
ac->ev.addRead = redisLibeventAddRead;
ac->ev.delRead = redisLibeventDelRead;
ac->ev.addWrite = redisLibeventAddWrite;
ac->ev.delWrite = redisLibeventDelWrite;
ac->ev.cleanup = redisLibeventCleanup;
ac->ev.scheduleTimer = redisLibeventSetTimeout;
ac->ev.data = e;

/* Initialize and install read/write events */
e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e);
e->base = base;
return REDIS_OK;
}
#endif

+ 0
- 119
俱乐部/Source/hiredis/adapters/libuv.h Bestand weergeven

@@ -1,119 +0,0 @@
#ifndef __HIREDIS_LIBUV_H__
#define __HIREDIS_LIBUV_H__
#include <stdlib.h>
#include <uv.h>
#include "../hiredis.h"
#include "../async.h"
#include <string.h>

typedef struct redisLibuvEvents {
redisAsyncContext* context;
uv_poll_t handle;
int events;
} redisLibuvEvents;


static void redisLibuvPoll(uv_poll_t* handle, int status, int events) {
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
int ev = (status ? p->events : events);

if (p->context != NULL && (ev & UV_READABLE)) {
redisAsyncHandleRead(p->context);
}
if (p->context != NULL && (ev & UV_WRITABLE)) {
redisAsyncHandleWrite(p->context);
}
}


static void redisLibuvAddRead(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;

p->events |= UV_READABLE;

uv_poll_start(&p->handle, p->events, redisLibuvPoll);
}


static void redisLibuvDelRead(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;

p->events &= ~UV_READABLE;

if (p->events) {
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
} else {
uv_poll_stop(&p->handle);
}
}


static void redisLibuvAddWrite(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;

p->events |= UV_WRITABLE;

uv_poll_start(&p->handle, p->events, redisLibuvPoll);
}


static void redisLibuvDelWrite(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;

p->events &= ~UV_WRITABLE;

if (p->events) {
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
} else {
uv_poll_stop(&p->handle);
}
}


static void on_close(uv_handle_t* handle) {
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;

free(p);
}


static void redisLibuvCleanup(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;

p->context = NULL; // indicate that context might no longer exist
uv_close((uv_handle_t*)&p->handle, on_close);
}


static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
redisContext *c = &(ac->c);

if (ac->ev.data != NULL) {
return REDIS_ERR;
}

ac->ev.addRead = redisLibuvAddRead;
ac->ev.delRead = redisLibuvDelRead;
ac->ev.addWrite = redisLibuvAddWrite;
ac->ev.delWrite = redisLibuvDelWrite;
ac->ev.cleanup = redisLibuvCleanup;

redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p));

if (!p) {
return REDIS_ERR;
}

memset(p, 0, sizeof(*p));

if (uv_poll_init(loop, &p->handle, c->fd) != 0) {
return REDIS_ERR;
}

ac->ev.data = p;
p->handle.data = p;
p->context = ac;

return REDIS_OK;
}
#endif

+ 0
- 114
俱乐部/Source/hiredis/adapters/macosx.h Bestand weergeven

@@ -1,114 +0,0 @@
//
// Created by Дмитрий Бахвалов on 13.07.15.
// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved.
//

#ifndef __HIREDIS_MACOSX_H__
#define __HIREDIS_MACOSX_H__

#include <CoreFoundation/CoreFoundation.h>

#include "../hiredis.h"
#include "../async.h"

typedef struct {
redisAsyncContext *context;
CFSocketRef socketRef;
CFRunLoopSourceRef sourceRef;
} RedisRunLoop;

static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) {
if( redisRunLoop != NULL ) {
if( redisRunLoop->sourceRef != NULL ) {
CFRunLoopSourceInvalidate(redisRunLoop->sourceRef);
CFRelease(redisRunLoop->sourceRef);
}
if( redisRunLoop->socketRef != NULL ) {
CFSocketInvalidate(redisRunLoop->socketRef);
CFRelease(redisRunLoop->socketRef);
}
free(redisRunLoop);
}
return REDIS_ERR;
}

static void redisMacOSAddRead(void *privdata) {
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack);
}

static void redisMacOSDelRead(void *privdata) {
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack);
}

static void redisMacOSAddWrite(void *privdata) {
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack);
}

static void redisMacOSDelWrite(void *privdata) {
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack);
}

static void redisMacOSCleanup(void *privdata) {
RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata;
freeRedisRunLoop(redisRunLoop);
}

static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) {
redisAsyncContext* context = (redisAsyncContext*) info;

switch (callbackType) {
case kCFSocketReadCallBack:
redisAsyncHandleRead(context);
break;

case kCFSocketWriteCallBack:
redisAsyncHandleWrite(context);
break;

default:
break;
}
}

static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) {
redisContext *redisCtx = &(redisAsyncCtx->c);

/* Nothing should be attached when something is already attached */
if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR;

RedisRunLoop* redisRunLoop = (RedisRunLoop*) calloc(1, sizeof(RedisRunLoop));
if( !redisRunLoop ) return REDIS_ERR;

/* Setup redis stuff */
redisRunLoop->context = redisAsyncCtx;

redisAsyncCtx->ev.addRead = redisMacOSAddRead;
redisAsyncCtx->ev.delRead = redisMacOSDelRead;
redisAsyncCtx->ev.addWrite = redisMacOSAddWrite;
redisAsyncCtx->ev.delWrite = redisMacOSDelWrite;
redisAsyncCtx->ev.cleanup = redisMacOSCleanup;
redisAsyncCtx->ev.data = redisRunLoop;

/* Initialize and install read/write events */
CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL };

redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd,
kCFSocketReadCallBack | kCFSocketWriteCallBack,
redisMacOSAsyncCallback,
&socketCtx);
if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop);

redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0);
if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop);

CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode);

return REDIS_OK;
}

#endif


+ 0
- 135
俱乐部/Source/hiredis/adapters/qt.h Bestand weergeven

@@ -1,135 +0,0 @@
/*-
* Copyright (C) 2014 Pietro Cerutti <gahr@gahr.ch>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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.
*/

#ifndef __HIREDIS_QT_H__
#define __HIREDIS_QT_H__
#include <QSocketNotifier>
#include "../async.h"

static void RedisQtAddRead(void *);
static void RedisQtDelRead(void *);
static void RedisQtAddWrite(void *);
static void RedisQtDelWrite(void *);
static void RedisQtCleanup(void *);

class RedisQtAdapter : public QObject {

Q_OBJECT

friend
void RedisQtAddRead(void * adapter) {
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
a->addRead();
}

friend
void RedisQtDelRead(void * adapter) {
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
a->delRead();
}

friend
void RedisQtAddWrite(void * adapter) {
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
a->addWrite();
}

friend
void RedisQtDelWrite(void * adapter) {
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
a->delWrite();
}

friend
void RedisQtCleanup(void * adapter) {
RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter);
a->cleanup();
}

public:
RedisQtAdapter(QObject * parent = 0)
: QObject(parent), m_ctx(0), m_read(0), m_write(0) { }

~RedisQtAdapter() {
if (m_ctx != 0) {
m_ctx->ev.data = NULL;
}
}

int setContext(redisAsyncContext * ac) {
if (ac->ev.data != NULL) {
return REDIS_ERR;
}
m_ctx = ac;
m_ctx->ev.data = this;
m_ctx->ev.addRead = RedisQtAddRead;
m_ctx->ev.delRead = RedisQtDelRead;
m_ctx->ev.addWrite = RedisQtAddWrite;
m_ctx->ev.delWrite = RedisQtDelWrite;
m_ctx->ev.cleanup = RedisQtCleanup;
return REDIS_OK;
}

private:
void addRead() {
if (m_read) return;
m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0);
connect(m_read, SIGNAL(activated(int)), this, SLOT(read()));
}

void delRead() {
if (!m_read) return;
delete m_read;
m_read = 0;
}

void addWrite() {
if (m_write) return;
m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0);
connect(m_write, SIGNAL(activated(int)), this, SLOT(write()));
}

void delWrite() {
if (!m_write) return;
delete m_write;
m_write = 0;
}

void cleanup() {
delRead();
delWrite();
}

private slots:
void read() { redisAsyncHandleRead(m_ctx); }
void write() { redisAsyncHandleWrite(m_ctx); }

private:
redisAsyncContext * m_ctx;
QSocketNotifier * m_read;
QSocketNotifier * m_write;
};

#endif /* !__HIREDIS_QT_H__ */

+ 0
- 65
俱乐部/Source/hiredis/alloc.c Bestand weergeven

@@ -1,65 +0,0 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* 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 Redis 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.
*/

#include "fmacros.h"
#include "alloc.h"
#include <string.h>

void *hi_malloc(size_t size) {
void *ptr = malloc(size);
if (ptr == NULL)
HIREDIS_OOM_HANDLER;

return ptr;
}

void *hi_calloc(size_t nmemb, size_t size) {
void *ptr = calloc(nmemb, size);
if (ptr == NULL)
HIREDIS_OOM_HANDLER;

return ptr;
}

void *hi_realloc(void *ptr, size_t size) {
void *newptr = realloc(ptr, size);
if (newptr == NULL)
HIREDIS_OOM_HANDLER;

return newptr;
}

char *hi_strdup(const char *str) {
char *newstr = strdup(str);
if (newstr == NULL)
HIREDIS_OOM_HANDLER;

return newstr;
}

+ 0
- 44
俱乐部/Source/hiredis/alloc.h Bestand weergeven

@@ -1,44 +0,0 @@
/*
* Copyright (c) 2020, Michael Grunder <michael dot grunder at gmail dot com>
*
* 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 Redis 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.
*/

#ifndef HIREDIS_ALLOC_H

#include <stdlib.h> /* for size_t */

#ifndef HIREDIS_OOM_HANDLER
#define HIREDIS_OOM_HANDLER abort()
#endif

void *hi_malloc(size_t size);
void *hi_calloc(size_t nmemb, size_t size);
void *hi_realloc(void *ptr, size_t size);
char *hi_strdup(const char *str);

#endif /* HIREDIS_ALLOC_H */

+ 0
- 24
俱乐部/Source/hiredis/appveyor.yml Bestand weergeven

@@ -1,24 +0,0 @@
# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin)
environment:
matrix:
- CYG_BASH: C:\cygwin64\bin\bash
CC: gcc
- CYG_BASH: C:\cygwin\bin\bash
CC: gcc
CFLAGS: -m32
CXXFLAGS: -m32
LDFLAGS: -m32

clone_depth: 1

# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
init:
- git config --global core.autocrlf input

# Install needed build dependencies
install:
- '%CYG_BASH% -lc "cygcheck -dc cygwin"'

build_script:
- 'echo building...'
- '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0</dev/null; mkdir build && cd build && cmake .. -G \"Unix Makefiles\" && make VERBOSE=1"'

+ 0
- 767
俱乐部/Source/hiredis/async.c Bestand weergeven

@@ -1,767 +0,0 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/

#include "fmacros.h"
#include "alloc.h"
#include <stdlib.h>
#include <string.h>
#ifndef _MSC_VER
#include <strings.h>
#endif
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include "async.h"
#include "net.h"
#include "dict.c"
#include "sds.h"
#include "win32.h"

#include "async_private.h"

/* Forward declaration of function in hiredis.c */
int __redisAppendCommand(redisContext *c, const char *cmd, size_t len);

/* Functions managing dictionary of callbacks for pub/sub. */
static unsigned int callbackHash(const void *key) {
return dictGenHashFunction((const unsigned char *)key,
sdslen((const sds)key));
}

static void *callbackValDup(void *privdata, const void *src) {
((void) privdata);
redisCallback *dup = hi_malloc(sizeof(*dup));
memcpy(dup,src,sizeof(*dup));
return dup;
}

static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) {
int l1, l2;
((void) privdata);

l1 = sdslen((const sds)key1);
l2 = sdslen((const sds)key2);
if (l1 != l2) return 0;
return memcmp(key1,key2,l1) == 0;
}

static void callbackKeyDestructor(void *privdata, void *key) {
((void) privdata);
sdsfree((sds)key);
}

static void callbackValDestructor(void *privdata, void *val) {
((void) privdata);
free(val);
}

static dictType callbackDict = {
callbackHash,
NULL,
callbackValDup,
callbackKeyCompare,
callbackKeyDestructor,
callbackValDestructor
};

static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
redisAsyncContext *ac;

ac = realloc(c,sizeof(redisAsyncContext));
if (ac == NULL)
return NULL;

c = &(ac->c);

/* The regular connect functions will always set the flag REDIS_CONNECTED.
* For the async API, we want to wait until the first write event is
* received up before setting this flag, so reset it here. */
c->flags &= ~REDIS_CONNECTED;

ac->err = 0;
ac->errstr = NULL;
ac->data = NULL;

ac->ev.data = NULL;
ac->ev.addRead = NULL;
ac->ev.delRead = NULL;
ac->ev.addWrite = NULL;
ac->ev.delWrite = NULL;
ac->ev.cleanup = NULL;
ac->ev.scheduleTimer = NULL;

ac->onConnect = NULL;
ac->onDisconnect = NULL;

ac->replies.head = NULL;
ac->replies.tail = NULL;
ac->sub.invalid.head = NULL;
ac->sub.invalid.tail = NULL;
ac->sub.channels = dictCreate(&callbackDict,NULL);
ac->sub.patterns = dictCreate(&callbackDict,NULL);
return ac;
}

/* We want the error field to be accessible directly instead of requiring
* an indirection to the redisContext struct. */
static void __redisAsyncCopyError(redisAsyncContext *ac) {
if (!ac)
return;

redisContext *c = &(ac->c);
ac->err = c->err;
ac->errstr = c->errstr;
}

redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options) {
redisOptions myOptions = *options;
redisContext *c;
redisAsyncContext *ac;

myOptions.options |= REDIS_OPT_NONBLOCK;
c = redisConnectWithOptions(&myOptions);
if (c == NULL) {
return NULL;
}
ac = redisAsyncInitialize(c);
if (ac == NULL) {
redisFree(c);
return NULL;
}
__redisAsyncCopyError(ac);
return ac;
}

redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
return redisAsyncConnectWithOptions(&options);
}

redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,
const char *source_addr) {
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.endpoint.tcp.source_addr = source_addr;
return redisAsyncConnectWithOptions(&options);
}

redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
const char *source_addr) {
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, ip, port);
options.options |= REDIS_OPT_REUSEADDR;
options.endpoint.tcp.source_addr = source_addr;
return redisAsyncConnectWithOptions(&options);
}

redisAsyncContext *redisAsyncConnectUnix(const char *path) {
redisOptions options = {0};
REDIS_OPTIONS_SET_UNIX(&options, path);
return redisAsyncConnectWithOptions(&options);
}

int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
if (ac->onConnect == NULL) {
ac->onConnect = fn;

/* The common way to detect an established connection is to wait for
* the first write event to be fired. This assumes the related event
* library functions are already set. */
_EL_ADD_WRITE(ac);
return REDIS_OK;
}
return REDIS_ERR;
}

int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) {
if (ac->onDisconnect == NULL) {
ac->onDisconnect = fn;
return REDIS_OK;
}
return REDIS_ERR;
}

/* Helper functions to push/shift callbacks */
static int __redisPushCallback(redisCallbackList *list, redisCallback *source) {
redisCallback *cb;

/* Copy callback from stack to heap */
cb = malloc(sizeof(*cb));
if (cb == NULL)
return REDIS_ERR_OOM;

if (source != NULL) {
memcpy(cb,source,sizeof(*cb));
cb->next = NULL;
}

/* Store callback in list */
if (list->head == NULL)
list->head = cb;
if (list->tail != NULL)
list->tail->next = cb;
list->tail = cb;
return REDIS_OK;
}

static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) {
redisCallback *cb = list->head;
if (cb != NULL) {
list->head = cb->next;
if (cb == list->tail)
list->tail = NULL;

/* Copy callback from heap to stack */
if (target != NULL)
memcpy(target,cb,sizeof(*cb));
free(cb);
return REDIS_OK;
}
return REDIS_ERR;
}

static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) {
redisContext *c = &(ac->c);
if (cb->fn != NULL) {
c->flags |= REDIS_IN_CALLBACK;
cb->fn(ac,reply,cb->privdata);
c->flags &= ~REDIS_IN_CALLBACK;
}
}

/* Helper function to free the context. */
static void __redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb;
dictIterator *it;
dictEntry *de;

/* Execute pending callbacks with NULL reply. */
while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK)
__redisRunCallback(ac,&cb,NULL);

/* Execute callbacks for invalid commands */
while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK)
__redisRunCallback(ac,&cb,NULL);

/* Run subscription callbacks callbacks with NULL reply */
it = dictGetIterator(ac->sub.channels);
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
dictRelease(ac->sub.channels);

it = dictGetIterator(ac->sub.patterns);
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
dictRelease(ac->sub.patterns);

/* Signal event lib to clean up */
_EL_CLEANUP(ac);

/* Execute disconnect callback. When redisAsyncFree() initiated destroying
* this context, the status will always be REDIS_OK. */
if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
if (c->flags & REDIS_FREEING) {
ac->onDisconnect(ac,REDIS_OK);
} else {
ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
}
}

/* Cleanup self */
redisFree(c);
}

/* Free the async context. When this function is called from a callback,
* control needs to be returned to redisProcessCallbacks() before actual
* free'ing. To do so, a flag is set on the context which is picked up by
* redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
void redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
c->flags |= REDIS_FREEING;
if (!(c->flags & REDIS_IN_CALLBACK))
__redisAsyncFree(ac);
}

/* Helper function to make the disconnect happen and clean up. */
void __redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);

/* Make sure error is accessible if there is any */
__redisAsyncCopyError(ac);

if (ac->err == 0) {
/* For clean disconnects, there should be no pending callbacks. */
int ret = __redisShiftCallback(&ac->replies,NULL);
assert(ret == REDIS_ERR);
} else {
/* Disconnection is caused by an error, make sure that pending
* callbacks cannot call new commands. */
c->flags |= REDIS_DISCONNECTING;
}

/* cleanup event library on disconnect.
* this is safe to call multiple times */
_EL_CLEANUP(ac);

/* For non-clean disconnects, __redisAsyncFree() will execute pending
* callbacks with a NULL-reply. */
if (!(c->flags & REDIS_NO_AUTO_FREE)) {
__redisAsyncFree(ac);
}
}

/* Tries to do a clean disconnect from Redis, meaning it stops new commands
* from being issued, but tries to flush the output buffer and execute
* callbacks for all remaining replies. When this function is called from a
* callback, there might be more replies and we can safely defer disconnecting
* to redisProcessCallbacks(). Otherwise, we can only disconnect immediately
* when there are no pending callbacks. */
void redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
c->flags |= REDIS_DISCONNECTING;

/** unset the auto-free flag here, because disconnect undoes this */
c->flags &= ~REDIS_NO_AUTO_FREE;
if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
__redisAsyncDisconnect(ac);
}

static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) {
redisContext *c = &(ac->c);
dict *callbacks;
redisCallback *cb;
dictEntry *de;
int pvariant;
char *stype;
sds sname;

/* Custom reply functions are not supported for pub/sub. This will fail
* very hard when they are used... */
if (reply->type == REDIS_REPLY_ARRAY) {
assert(reply->elements >= 2);
assert(reply->element[0]->type == REDIS_REPLY_STRING);
stype = reply->element[0]->str;
pvariant = (tolower(stype[0]) == 'p') ? 1 : 0;

if (pvariant)
callbacks = ac->sub.patterns;
else
callbacks = ac->sub.channels;

/* Locate the right callback */
assert(reply->element[1]->type == REDIS_REPLY_STRING);
sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
de = dictFind(callbacks,sname);
if (de != NULL) {
cb = dictGetEntryVal(de);

/* If this is an subscribe reply decrease pending counter. */
if (strcasecmp(stype+pvariant,"subscribe") == 0) {
cb->pending_subs -= 1;
}

memcpy(dstcb,cb,sizeof(*dstcb));

/* If this is an unsubscribe message, remove it. */
if (strcasecmp(stype+pvariant,"unsubscribe") == 0) {
if (cb->pending_subs == 0)
dictDelete(callbacks,sname);

/* If this was the last unsubscribe message, revert to
* non-subscribe mode. */
assert(reply->element[2]->type == REDIS_REPLY_INTEGER);

/* Unset subscribed flag only when no pipelined pending subscribe. */
if (reply->element[2]->integer == 0
&& dictSize(ac->sub.channels) == 0
&& dictSize(ac->sub.patterns) == 0)
c->flags &= ~REDIS_SUBSCRIBED;
}
}
sdsfree(sname);
} else {
/* Shift callback for invalid commands. */
__redisShiftCallback(&ac->sub.invalid,dstcb);
}
return REDIS_OK;
}

void redisProcessCallbacks(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb = {NULL, NULL, 0, NULL};
void *reply = NULL;
int status;

while((status = redisGetReply(c,&reply)) == REDIS_OK) {
if (reply == NULL) {
/* When the connection is being disconnected and there are
* no more replies, this is the cue to really disconnect. */
if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0
&& ac->replies.head == NULL) {
__redisAsyncDisconnect(ac);
return;
}

/* If monitor mode, repush callback */
if(c->flags & REDIS_MONITORING) {
__redisPushCallback(&ac->replies,&cb);
}

/* When the connection is not being disconnected, simply stop
* trying to get replies and wait for the next loop tick. */
break;
}

/* Even if the context is subscribed, pending regular callbacks will
* get a reply before pub/sub messages arrive. */
if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
/*
* A spontaneous reply in a not-subscribed context can be the error
* reply that is sent when a new connection exceeds the maximum
* number of allowed connections on the server side.
*
* This is seen as an error instead of a regular reply because the
* server closes the connection after sending it.
*
* To prevent the error from being overwritten by an EOF error the
* connection is closed here. See issue #43.
*
* Another possibility is that the server is loading its dataset.
* In this case we also want to close the connection, and have the
* user wait until the server is ready to take our request.
*/
if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) {
c->err = REDIS_ERR_OTHER;
snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str);
c->reader->fn->freeObject(reply);
__redisAsyncDisconnect(ac);
return;
}
/* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */
assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING));
if(c->flags & REDIS_SUBSCRIBED)
__redisGetSubscribeCallback(ac,reply,&cb);
}

if (cb.fn != NULL) {
__redisRunCallback(ac,&cb,reply);
c->reader->fn->freeObject(reply);

/* Proceed with free'ing when redisAsyncFree() was called. */
if (c->flags & REDIS_FREEING) {
__redisAsyncFree(ac);
return;
}
} else {
/* No callback for this reply. This can either be a NULL callback,
* or there were no callbacks to begin with. Either way, don't
* abort with an error, but simply ignore it because the client
* doesn't know what the server will spit out over the wire. */
c->reader->fn->freeObject(reply);
}
}

/* Disconnect when there was an error reading the reply */
if (status != REDIS_OK)
__redisAsyncDisconnect(ac);
}

/* Internal helper function to detect socket status the first time a read or
* write event fires. When connecting was not successful, the connect callback
* is called with a REDIS_ERR status and the context is free'd. */
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
int completed = 0;
redisContext *c = &(ac->c);
if (redisCheckConnectDone(c, &completed) == REDIS_ERR) {
/* Error! */
redisCheckSocketError(c);
if (ac->onConnect) ac->onConnect(ac, REDIS_ERR);
__redisAsyncDisconnect(ac);
return REDIS_ERR;
} else if (completed == 1) {
/* connected! */
if (ac->onConnect) ac->onConnect(ac, REDIS_OK);
c->flags |= REDIS_CONNECTED;
return REDIS_OK;
} else {
return REDIS_OK;
}
}

void redisAsyncRead(redisAsyncContext *ac) {
redisContext *c = &(ac->c);

if (redisBufferRead(c) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
/* Always re-schedule reads */
_EL_ADD_READ(ac);
redisProcessCallbacks(ac);
}
}

/* This function should be called when the socket is readable.
* It processes all replies that can be read and executes their callbacks.
*/
void redisAsyncHandleRead(redisAsyncContext *ac) {
redisContext *c = &(ac->c);

if (!(c->flags & REDIS_CONNECTED)) {
/* Abort connect was not successful. */
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
return;
/* Try again later when the context is still not connected. */
if (!(c->flags & REDIS_CONNECTED))
return;
}

c->funcs->async_read(ac);
}

void redisAsyncWrite(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
int done = 0;

if (redisBufferWrite(c,&done) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
/* Continue writing when not done, stop writing otherwise */
if (!done)
_EL_ADD_WRITE(ac);
else
_EL_DEL_WRITE(ac);

/* Always schedule reads after writes */
_EL_ADD_READ(ac);
}
}

void redisAsyncHandleWrite(redisAsyncContext *ac) {
redisContext *c = &(ac->c);

if (!(c->flags & REDIS_CONNECTED)) {
/* Abort connect was not successful. */
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
return;
/* Try again later when the context is still not connected. */
if (!(c->flags & REDIS_CONNECTED))
return;
}

c->funcs->async_write(ac);
}

void __redisSetError(redisContext *c, int type, const char *str);

void redisAsyncHandleTimeout(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb;

if ((c->flags & REDIS_CONNECTED) && ac->replies.head == NULL) {
/* Nothing to do - just an idle timeout */
return;
}

if (!c->err) {
__redisSetError(c, REDIS_ERR_TIMEOUT, "Timeout");
}

if (!(c->flags & REDIS_CONNECTED) && ac->onConnect) {
ac->onConnect(ac, REDIS_ERR);
}

while (__redisShiftCallback(&ac->replies, &cb) == REDIS_OK) {
__redisRunCallback(ac, &cb, NULL);
}

/**
* TODO: Don't automatically sever the connection,
* rather, allow to ignore <x> responses before the queue is clear
*/
__redisAsyncDisconnect(ac);
}

/* Sets a pointer to the first argument and its length starting at p. Returns
* the number of bytes to skip to get to the following argument. */
static const char *nextArgument(const char *start, const char **str, size_t *len) {
const char *p = start;
if (p[0] != '$') {
p = strchr(p,'$');
if (p == NULL) return NULL;
}

*len = (int)strtol(p+1,NULL,10);
p = strchr(p,'\r');
assert(p);
*str = p+2;
return p+2+(*len)+2;
}

/* Helper function for the redisAsyncCommand* family of functions. Writes a
* formatted command to the output buffer and registers the provided callback
* function with the context. */
static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) {
redisContext *c = &(ac->c);
redisCallback cb;
struct dict *cbdict;
dictEntry *de;
redisCallback *existcb;
int pvariant, hasnext;
const char *cstr, *astr;
size_t clen, alen;
const char *p;
sds sname;
int ret;

/* Don't accept new commands when the connection is about to be closed. */
if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR;

/* Setup callback */
cb.fn = fn;
cb.privdata = privdata;
cb.pending_subs = 1;

/* Find out which command will be appended. */
p = nextArgument(cmd,&cstr,&clen);
assert(p != NULL);
hasnext = (p[0] == '$');
pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0;
cstr += pvariant;
clen -= pvariant;

if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) {
c->flags |= REDIS_SUBSCRIBED;

/* Add every channel/pattern to the list of subscription callbacks. */
while ((p = nextArgument(p,&astr,&alen)) != NULL) {
sname = sdsnewlen(astr,alen);
if (pvariant)
cbdict = ac->sub.patterns;
else
cbdict = ac->sub.channels;

de = dictFind(cbdict,sname);

if (de != NULL) {
existcb = dictGetEntryVal(de);
cb.pending_subs = existcb->pending_subs + 1;
}

ret = dictReplace(cbdict,sname,&cb);

if (ret == 0) sdsfree(sname);
}
} else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) {
/* It is only useful to call (P)UNSUBSCRIBE when the context is
* subscribed to one or more channels or patterns. */
if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR;

/* (P)UNSUBSCRIBE does not have its own response: every channel or
* pattern that is unsubscribed will receive a message. This means we
* should not append a callback function for this command. */
} else if(strncasecmp(cstr,"monitor\r\n",9) == 0) {
/* Set monitor flag and push callback */
c->flags |= REDIS_MONITORING;
__redisPushCallback(&ac->replies,&cb);
} else {
if (c->flags & REDIS_SUBSCRIBED)
/* This will likely result in an error reply, but it needs to be
* received and passed to the callback. */
__redisPushCallback(&ac->sub.invalid,&cb);
else
__redisPushCallback(&ac->replies,&cb);
}

__redisAppendCommand(c,cmd,len);

/* Always schedule a write when the write buffer is non-empty */
_EL_ADD_WRITE(ac);

return REDIS_OK;
}

int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) {
char *cmd;
int len;
int status;
len = redisvFormatCommand(&cmd,format,ap);

/* We don't want to pass -1 or -2 to future functions as a length. */
if (len < 0)
return REDIS_ERR;

status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
free(cmd);
return status;
}

int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) {
va_list ap;
int status;
va_start(ap,format);
status = redisvAsyncCommand(ac,fn,privdata,format,ap);
va_end(ap);
return status;
}

int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) {
sds cmd;
int len;
int status;
len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
if (len < 0)
return REDIS_ERR;
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
sdsfree(cmd);
return status;
}

int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) {
int status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
return status;
}

void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv) {
if (!ac->c.timeout) {
ac->c.timeout = hi_calloc(1, sizeof(tv));
}

if (tv.tv_sec == ac->c.timeout->tv_sec &&
tv.tv_usec == ac->c.timeout->tv_usec) {
return;
}

*ac->c.timeout = tv;
}

+ 0
- 142
俱乐部/Source/hiredis/async.h Bestand weergeven

@@ -1,142 +0,0 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/

#ifndef __HIREDIS_ASYNC_H
#define __HIREDIS_ASYNC_H
#include "hiredis.h"

#ifdef __cplusplus
extern "C" {
#endif

struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
struct dict; /* dictionary header is included in async.c */

/* Reply callback prototype and container */
typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
typedef struct redisCallback {
struct redisCallback *next; /* simple singly linked list */
redisCallbackFn *fn;
int pending_subs;
void *privdata;
} redisCallback;

/* List of callbacks for either regular replies or pub/sub */
typedef struct redisCallbackList {
redisCallback *head, *tail;
} redisCallbackList;

/* Connection callback prototypes */
typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
typedef void(redisTimerCallback)(void *timer, void *privdata);

/* Context for an async connection to Redis */
typedef struct redisAsyncContext {
/* Hold the regular context, so it can be realloc'ed. */
redisContext c;

/* Setup error flags so they can be used directly. */
int err;
char *errstr;

/* Not used by hiredis */
void *data;

/* Event library data and hooks */
struct {
void *data;

/* Hooks that are called when the library expects to start
* reading/writing. These functions should be idempotent. */
void (*addRead)(void *privdata);
void (*delRead)(void *privdata);
void (*addWrite)(void *privdata);
void (*delWrite)(void *privdata);
void (*cleanup)(void *privdata);
void (*scheduleTimer)(void *privdata, struct timeval tv);
} ev;

/* Called when either the connection is terminated due to an error or per
* user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
redisDisconnectCallback *onDisconnect;

/* Called when the first write event was received. */
redisConnectCallback *onConnect;

/* Regular command callbacks */
redisCallbackList replies;

/* Address used for connect() */
struct sockaddr *saddr;
size_t addrlen;

/* Subscription callbacks */
struct {
redisCallbackList invalid;
struct dict *channels;
struct dict *patterns;
} sub;
} redisAsyncContext;

/* Functions that proxy to hiredis */
redisAsyncContext *redisAsyncConnectWithOptions(const redisOptions *options);
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port,
const char *source_addr);
redisAsyncContext *redisAsyncConnectUnix(const char *path);
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);

void redisAsyncSetTimeout(redisAsyncContext *ac, struct timeval tv);
void redisAsyncDisconnect(redisAsyncContext *ac);
void redisAsyncFree(redisAsyncContext *ac);

/* Handle read/write events */
void redisAsyncHandleRead(redisAsyncContext *ac);
void redisAsyncHandleWrite(redisAsyncContext *ac);
void redisAsyncHandleTimeout(redisAsyncContext *ac);
void redisAsyncRead(redisAsyncContext *ac);
void redisAsyncWrite(redisAsyncContext *ac);

/* Command functions for an async context. Write the command to the
* output buffer and register the provided callback. */
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len);

#ifdef __cplusplus
}
#endif

#endif

+ 0
- 72
俱乐部/Source/hiredis/async_private.h Bestand weergeven

@@ -1,72 +0,0 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/

#ifndef __HIREDIS_ASYNC_PRIVATE_H
#define __HIREDIS_ASYNC_PRIVATE_H

#define _EL_ADD_READ(ctx) \
do { \
refreshTimeout(ctx); \
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
} while (0)
#define _EL_DEL_READ(ctx) do { \
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
} while(0)
#define _EL_ADD_WRITE(ctx) \
do { \
refreshTimeout(ctx); \
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
} while (0)
#define _EL_DEL_WRITE(ctx) do { \
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
} while(0)
#define _EL_CLEANUP(ctx) do { \
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
ctx->ev.cleanup = NULL; \
} while(0);

static inline void refreshTimeout(redisAsyncContext *ctx) {
if (ctx->c.timeout && ctx->ev.scheduleTimer &&
(ctx->c.timeout->tv_sec || ctx->c.timeout->tv_usec)) {
ctx->ev.scheduleTimer(ctx->ev.data, *ctx->c.timeout);
// } else {
// printf("Not scheduling timer.. (tmo=%p)\n", ctx->c.timeout);
// if (ctx->c.timeout){
// printf("tv_sec: %u. tv_usec: %u\n", ctx->c.timeout->tv_sec,
// ctx->c.timeout->tv_usec);
// }
}
}

void __redisAsyncDisconnect(redisAsyncContext *ac);
void redisProcessCallbacks(redisAsyncContext *ac);

#endif /* __HIREDIS_ASYNC_PRIVATE_H */

+ 0
- 339
俱乐部/Source/hiredis/dict.c Bestand weergeven

@@ -1,339 +0,0 @@
/* Hash table implementation.
*
* This file implements in memory hash tables with insert/del/replace/find/
* get-random-element operations. Hash tables will auto resize if needed
* tables of power of two in size are used, collisions are handled by
* chaining. See the source code for more information... :)
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* 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 Redis 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.
*/

#include "fmacros.h"
#include "alloc.h"
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include "dict.h"

/* -------------------------- private prototypes ---------------------------- */

static int _dictExpandIfNeeded(dict *ht);
static unsigned long _dictNextPower(unsigned long size);
static int _dictKeyIndex(dict *ht, const void *key);
static int _dictInit(dict *ht, dictType *type, void *privDataPtr);

/* -------------------------- hash functions -------------------------------- */

/* Generic hash function (a popular one from Bernstein).
* I tested a few and this was the best. */
static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
unsigned int hash = 5381;

while (len--)
hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
return hash;
}

/* ----------------------------- API implementation ------------------------- */

/* Reset an hashtable already initialized with ht_init().
* NOTE: This function should only called by ht_destroy(). */
static void _dictReset(dict *ht) {
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
}

/* Create a new hash table */
static dict *dictCreate(dictType *type, void *privDataPtr) {
dict *ht = hi_malloc(sizeof(*ht));
_dictInit(ht,type,privDataPtr);
return ht;
}

/* Initialize the hash table */
static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
_dictReset(ht);
ht->type = type;
ht->privdata = privDataPtr;
return DICT_OK;
}

/* Expand or create the hashtable */
static int dictExpand(dict *ht, unsigned long size) {
dict n; /* the new hashtable */
unsigned long realsize = _dictNextPower(size), i;

/* the size is invalid if it is smaller than the number of
* elements already inside the hashtable */
if (ht->used > size)
return DICT_ERR;

_dictInit(&n, ht->type, ht->privdata);
n.size = realsize;
n.sizemask = realsize-1;
n.table = calloc(realsize,sizeof(dictEntry*));

/* Copy all the elements from the old to the new table:
* note that if the old hash table is empty ht->size is zero,
* so dictExpand just creates an hash table. */
n.used = ht->used;
for (i = 0; i < ht->size && ht->used > 0; i++) {
dictEntry *he, *nextHe;

if (ht->table[i] == NULL) continue;

/* For each hash entry on this slot... */
he = ht->table[i];
while(he) {
unsigned int h;

nextHe = he->next;
/* Get the new element index */
h = dictHashKey(ht, he->key) & n.sizemask;
he->next = n.table[h];
n.table[h] = he;
ht->used--;
/* Pass to the next element */
he = nextHe;
}
}
assert(ht->used == 0);
free(ht->table);

/* Remap the new hashtable in the old */
*ht = n;
return DICT_OK;
}

/* Add an element to the target hash table */
static int dictAdd(dict *ht, void *key, void *val) {
int index;
dictEntry *entry;

/* Get the index of the new element, or -1 if
* the element already exists. */
if ((index = _dictKeyIndex(ht, key)) == -1)
return DICT_ERR;

/* Allocates the memory and stores key */
entry = hi_malloc(sizeof(*entry));
entry->next = ht->table[index];
ht->table[index] = entry;

/* Set the hash entry fields. */
dictSetHashKey(ht, entry, key);
dictSetHashVal(ht, entry, val);
ht->used++;
return DICT_OK;
}

/* Add an element, discarding the old if the key already exists.
* Return 1 if the key was added from scratch, 0 if there was already an
* element with such key and dictReplace() just performed a value update
* operation. */
static int dictReplace(dict *ht, void *key, void *val) {
dictEntry *entry, auxentry;

/* Try to add the element. If the key
* does not exists dictAdd will succeed. */
if (dictAdd(ht, key, val) == DICT_OK)
return 1;
/* It already exists, get the entry */
entry = dictFind(ht, key);
/* Free the old value and set the new one */
/* Set the new value and free the old one. Note that it is important
* to do that in this order, as the value may just be exactly the same
* as the previous one. In this context, think to reference counting,
* you want to increment (set), and then decrement (free), and not the
* reverse. */
auxentry = *entry;
dictSetHashVal(ht, entry, val);
dictFreeEntryVal(ht, &auxentry);
return 0;
}

/* Search and remove an element */
static int dictDelete(dict *ht, const void *key) {
unsigned int h;
dictEntry *de, *prevde;

if (ht->size == 0)
return DICT_ERR;
h = dictHashKey(ht, key) & ht->sizemask;
de = ht->table[h];

prevde = NULL;
while(de) {
if (dictCompareHashKeys(ht,key,de->key)) {
/* Unlink the element from the list */
if (prevde)
prevde->next = de->next;
else
ht->table[h] = de->next;

dictFreeEntryKey(ht,de);
dictFreeEntryVal(ht,de);
free(de);
ht->used--;
return DICT_OK;
}
prevde = de;
de = de->next;
}
return DICT_ERR; /* not found */
}

/* Destroy an entire hash table */
static int _dictClear(dict *ht) {
unsigned long i;

/* Free all the elements */
for (i = 0; i < ht->size && ht->used > 0; i++) {
dictEntry *he, *nextHe;

if ((he = ht->table[i]) == NULL) continue;
while(he) {
nextHe = he->next;
dictFreeEntryKey(ht, he);
dictFreeEntryVal(ht, he);
free(he);
ht->used--;
he = nextHe;
}
}
/* Free the table and the allocated cache structure */
free(ht->table);
/* Re-initialize the table */
_dictReset(ht);
return DICT_OK; /* never fails */
}

/* Clear & Release the hash table */
static void dictRelease(dict *ht) {
_dictClear(ht);
free(ht);
}

static dictEntry *dictFind(dict *ht, const void *key) {
dictEntry *he;
unsigned int h;

if (ht->size == 0) return NULL;
h = dictHashKey(ht, key) & ht->sizemask;
he = ht->table[h];
while(he) {
if (dictCompareHashKeys(ht, key, he->key))
return he;
he = he->next;
}
return NULL;
}

static dictIterator *dictGetIterator(dict *ht) {
dictIterator *iter = hi_malloc(sizeof(*iter));

iter->ht = ht;
iter->index = -1;
iter->entry = NULL;
iter->nextEntry = NULL;
return iter;
}

static dictEntry *dictNext(dictIterator *iter) {
while (1) {
if (iter->entry == NULL) {
iter->index++;
if (iter->index >=
(signed)iter->ht->size) break;
iter->entry = iter->ht->table[iter->index];
} else {
iter->entry = iter->nextEntry;
}
if (iter->entry) {
/* We need to save the 'next' here, the iterator user
* may delete the entry we are returning. */
iter->nextEntry = iter->entry->next;
return iter->entry;
}
}
return NULL;
}

static void dictReleaseIterator(dictIterator *iter) {
free(iter);
}

/* ------------------------- private functions ------------------------------ */

/* Expand the hash table if needed */
static int _dictExpandIfNeeded(dict *ht) {
/* If the hash table is empty expand it to the initial size,
* if the table is "full" double its size. */
if (ht->size == 0)
return dictExpand(ht, DICT_HT_INITIAL_SIZE);
if (ht->used == ht->size)
return dictExpand(ht, ht->size*2);
return DICT_OK;
}

/* Our hash table capability is a power of two */
static unsigned long _dictNextPower(unsigned long size) {
unsigned long i = DICT_HT_INITIAL_SIZE;

if (size >= LONG_MAX) return LONG_MAX;
while(1) {
if (i >= size)
return i;
i *= 2;
}
}

/* Returns the index of a free slot that can be populated with
* an hash entry for the given 'key'.
* If the key already exists, -1 is returned. */
static int _dictKeyIndex(dict *ht, const void *key) {
unsigned int h;
dictEntry *he;

/* Expand the hashtable if needed */
if (_dictExpandIfNeeded(ht) == DICT_ERR)
return -1;
/* Compute the key hash value */
h = dictHashKey(ht, key) & ht->sizemask;
/* Search if this slot does not already contain the given key */
he = ht->table[h];
while(he) {
if (dictCompareHashKeys(ht, key, he->key))
return -1;
he = he->next;
}
return h;
}


+ 0
- 126
俱乐部/Source/hiredis/dict.h Bestand weergeven

@@ -1,126 +0,0 @@
/* Hash table implementation.
*
* This file implements in memory hash tables with insert/del/replace/find/
* get-random-element operations. Hash tables will auto resize if needed
* tables of power of two in size are used, collisions are handled by
* chaining. See the source code for more information... :)
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* 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 Redis 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.
*/

#ifndef __DICT_H
#define __DICT_H

#define DICT_OK 0
#define DICT_ERR 1

/* Unused arguments generate annoying warnings... */
#define DICT_NOTUSED(V) ((void) V)

typedef struct dictEntry {
void *key;
void *val;
struct dictEntry *next;
} dictEntry;

typedef struct dictType {
unsigned int (*hashFunction)(const void *key);
void *(*keyDup)(void *privdata, const void *key);
void *(*valDup)(void *privdata, const void *obj);
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
} dictType;

typedef struct dict {
dictEntry **table;
dictType *type;
unsigned long size;
unsigned long sizemask;
unsigned long used;
void *privdata;
} dict;

typedef struct dictIterator {
dict *ht;
int index;
dictEntry *entry, *nextEntry;
} dictIterator;

/* This is the initial size of every hash table */
#define DICT_HT_INITIAL_SIZE 4

/* ------------------------------- Macros ------------------------------------*/
#define dictFreeEntryVal(ht, entry) \
if ((ht)->type->valDestructor) \
(ht)->type->valDestructor((ht)->privdata, (entry)->val)

#define dictSetHashVal(ht, entry, _val_) do { \
if ((ht)->type->valDup) \
entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
else \
entry->val = (_val_); \
} while(0)

#define dictFreeEntryKey(ht, entry) \
if ((ht)->type->keyDestructor) \
(ht)->type->keyDestructor((ht)->privdata, (entry)->key)

#define dictSetHashKey(ht, entry, _key_) do { \
if ((ht)->type->keyDup) \
entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
else \
entry->key = (_key_); \
} while(0)

#define dictCompareHashKeys(ht, key1, key2) \
(((ht)->type->keyCompare) ? \
(ht)->type->keyCompare((ht)->privdata, key1, key2) : \
(key1) == (key2))

#define dictHashKey(ht, key) (ht)->type->hashFunction(key)

#define dictGetEntryKey(he) ((he)->key)
#define dictGetEntryVal(he) ((he)->val)
#define dictSlots(ht) ((ht)->size)
#define dictSize(ht) ((ht)->used)

/* API */
static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
static dict *dictCreate(dictType *type, void *privDataPtr);
static int dictExpand(dict *ht, unsigned long size);
static int dictAdd(dict *ht, void *key, void *val);
static int dictReplace(dict *ht, void *key, void *val);
static int dictDelete(dict *ht, const void *key);
static void dictRelease(dict *ht);
static dictEntry * dictFind(dict *ht, const void *key);
static dictIterator *dictGetIterator(dict *ht);
static dictEntry *dictNext(dictIterator *iter);
static void dictReleaseIterator(dictIterator *iter);

#endif /* __DICT_H */

+ 0
- 62
俱乐部/Source/hiredis/examples/example-ae.c Bestand weergeven

@@ -1,62 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/ae.h>

/* Put event loop in the global scope, so it can be explicitly stopped */
static aeEventLoop *loop;

void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);

/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}

void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
aeStop(loop);
return;
}

printf("Connected...\n");
}

void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
aeStop(loop);
return;
}

printf("Disconnected...\n");
aeStop(loop);
}

int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}

loop = aeCreateEventLoop(64);
redisAeAttach(loop, c);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
aeMain(loop);
return 0;
}


+ 0
- 73
俱乐部/Source/hiredis/examples/example-glib.c Bestand weergeven

@@ -1,73 +0,0 @@
#include <stdlib.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/glib.h>

static GMainLoop *mainloop;

static void
connect_cb (const redisAsyncContext *ac G_GNUC_UNUSED,
int status)
{
if (status != REDIS_OK) {
g_printerr("Failed to connect: %s\n", ac->errstr);
g_main_loop_quit(mainloop);
} else {
g_printerr("Connected...\n");
}
}

static void
disconnect_cb (const redisAsyncContext *ac G_GNUC_UNUSED,
int status)
{
if (status != REDIS_OK) {
g_error("Failed to disconnect: %s", ac->errstr);
} else {
g_printerr("Disconnected...\n");
g_main_loop_quit(mainloop);
}
}

static void
command_cb(redisAsyncContext *ac,
gpointer r,
gpointer user_data G_GNUC_UNUSED)
{
redisReply *reply = r;

if (reply) {
g_print("REPLY: %s\n", reply->str);
}

redisAsyncDisconnect(ac);
}

gint
main (gint argc G_GNUC_UNUSED,
gchar *argv[] G_GNUC_UNUSED)
{
redisAsyncContext *ac;
GMainContext *context = NULL;
GSource *source;

ac = redisAsyncConnect("127.0.0.1", 6379);
if (ac->err) {
g_printerr("%s\n", ac->errstr);
exit(EXIT_FAILURE);
}

source = redis_source_new(ac);
mainloop = g_main_loop_new(context, FALSE);
g_source_attach(source, context);

redisAsyncSetConnectCallback(ac, connect_cb);
redisAsyncSetDisconnectCallback(ac, disconnect_cb);
redisAsyncCommand(ac, command_cb, NULL, "SET key 1234");
redisAsyncCommand(ac, command_cb, NULL, "GET key");

g_main_loop_run(mainloop);

return EXIT_SUCCESS;
}

+ 0
- 58
俱乐部/Source/hiredis/examples/example-ivykis.c Bestand weergeven

@@ -1,58 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/ivykis.h>

void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);

/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}

void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}

void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}

int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);

iv_init();

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}

redisIvykisAttach(c);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");

iv_main();

iv_deinit();

return 0;
}

+ 0
- 52
俱乐部/Source/hiredis/examples/example-libev.c Bestand weergeven

@@ -1,52 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/libev.h>

void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);

/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}

void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}

void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}

int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}

redisLibevAttach(EV_DEFAULT_ c);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
ev_loop(EV_DEFAULT_ 0);
return 0;
}

+ 0
- 73
俱乐部/Source/hiredis/examples/example-libevent-ssl.c Bestand weergeven

@@ -1,73 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <hiredis.h>
#include <hiredis_ssl.h>
#include <async.h>
#include <adapters/libevent.h>

void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);

/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}

void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}

void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}

int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
struct event_base *base = event_base_new();
if (argc < 5) {
fprintf(stderr,
"Usage: %s <key> <host> <port> <cert> <certKey> [ca]\n", argv[0]);
exit(1);
}

const char *value = argv[1];
size_t nvalue = strlen(value);

const char *hostname = argv[2];
int port = atoi(argv[3]);

const char *cert = argv[4];
const char *certKey = argv[5];
const char *caCert = argc > 5 ? argv[6] : NULL;

redisAsyncContext *c = redisAsyncConnect(hostname, port);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
if (redisSecureConnection(&c->c, caCert, cert, certKey, "sni") != REDIS_OK) {
printf("SSL Error!\n");
exit(1);
}

redisLibeventAttach(c,base);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", value, nvalue);
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
event_base_dispatch(base);
return 0;
}

+ 0
- 64
俱乐部/Source/hiredis/examples/example-libevent.c Bestand weergeven

@@ -1,64 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/libevent.h>

void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) {
if (c->errstr) {
printf("errstr: %s\n", c->errstr);
}
return;
}
printf("argv[%s]: %s\n", (char*)privdata, reply->str);

/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}

void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}

void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}

int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
struct event_base *base = event_base_new();
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, "127.0.0.1", 6379);
struct timeval tv = {0};
tv.tv_sec = 1;
options.timeout = &tv;


redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}

redisLibeventAttach(c,base);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
event_base_dispatch(base);
return 0;
}

+ 0
- 53
俱乐部/Source/hiredis/examples/example-libuv.c Bestand weergeven

@@ -1,53 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/libuv.h>

void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);

/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}

void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}

void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}

int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
uv_loop_t* loop = uv_default_loop();

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}

redisLibuvAttach(c,loop);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}

+ 0
- 66
俱乐部/Source/hiredis/examples/example-macosx.c Bestand weergeven

@@ -1,66 +0,0 @@
//
// Created by Дмитрий Бахвалов on 13.07.15.
// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved.
//

#include <stdio.h>

#include <hiredis.h>
#include <async.h>
#include <adapters/macosx.h>

void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);

/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}

void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}

void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
CFRunLoopStop(CFRunLoopGetCurrent());
printf("Disconnected...\n");
}

int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);

CFRunLoopRef loop = CFRunLoopGetCurrent();
if( !loop ) {
printf("Error: Cannot get current run loop\n");
return 1;
}

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}

redisMacOSAttach(c, loop);

redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);

redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");

CFRunLoopRun();

return 0;
}


+ 0
- 46
俱乐部/Source/hiredis/examples/example-qt.cpp Bestand weergeven

@@ -1,46 +0,0 @@
#include <iostream>
using namespace std;

#include <QCoreApplication>
#include <QTimer>

#include "example-qt.h"

void getCallback(redisAsyncContext *, void * r, void * privdata) {

redisReply * reply = static_cast<redisReply *>(r);
ExampleQt * ex = static_cast<ExampleQt *>(privdata);
if (reply == nullptr || ex == nullptr) return;

cout << "key: " << reply->str << endl;

ex->finish();
}

void ExampleQt::run() {

m_ctx = redisAsyncConnect("localhost", 6379);

if (m_ctx->err) {
cerr << "Error: " << m_ctx->errstr << endl;
redisAsyncFree(m_ctx);
emit finished();
}

m_adapter.setContext(m_ctx);

redisAsyncCommand(m_ctx, NULL, NULL, "SET key %s", m_value);
redisAsyncCommand(m_ctx, getCallback, this, "GET key");
}

int main (int argc, char **argv) {

QCoreApplication app(argc, argv);

ExampleQt example(argv[argc-1]);

QObject::connect(&example, SIGNAL(finished()), &app, SLOT(quit()));
QTimer::singleShot(0, &example, SLOT(run()));

return app.exec();
}

+ 0
- 32
俱乐部/Source/hiredis/examples/example-qt.h Bestand weergeven

@@ -1,32 +0,0 @@
#ifndef __HIREDIS_EXAMPLE_QT_H
#define __HIREDIS_EXAMPLE_QT_H

#include <adapters/qt.h>

class ExampleQt : public QObject {

Q_OBJECT

public:
ExampleQt(const char * value, QObject * parent = 0)
: QObject(parent), m_value(value) {}

signals:
void finished();

public slots:
void run();

private:
void finish() { emit finished(); }

private:
const char * m_value;
redisAsyncContext * m_ctx;
RedisQtAdapter m_adapter;

friend
void getCallback(redisAsyncContext *, void *, void *);
};

#endif /* !__HIREDIS_EXAMPLE_QT_H */

+ 0
- 97
俱乐部/Source/hiredis/examples/example-ssl.c Bestand weergeven

@@ -1,97 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <hiredis.h>
#include <hiredis_ssl.h>

int main(int argc, char **argv) {
unsigned int j;
redisContext *c;
redisReply *reply;
if (argc < 4) {
printf("Usage: %s <host> <port> <cert> <key> [ca]\n", argv[0]);
exit(1);
}
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
int port = atoi(argv[2]);
const char *cert = argv[3];
const char *key = argv[4];
const char *ca = argc > 4 ? argv[5] : NULL;

struct timeval tv = { 1, 500000 }; // 1.5 seconds
redisOptions options = {0};
REDIS_OPTIONS_SET_TCP(&options, hostname, port);
options.timeout = &tv;
c = redisConnectWithOptions(&options);

if (c == NULL || c->err) {
if (c) {
printf("Connection error: %s\n", c->errstr);
redisFree(c);
} else {
printf("Connection error: can't allocate redis context\n");
}
exit(1);
}

if (redisSecureConnection(c, ca, cert, key, "sni") != REDIS_OK) {
printf("Couldn't initialize SSL!\n");
printf("Error: %s\n", c->errstr);
redisFree(c);
exit(1);
}

/* PING server */
reply = redisCommand(c,"PING");
printf("PING: %s\n", reply->str);
freeReplyObject(reply);

/* Set a key */
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
printf("SET: %s\n", reply->str);
freeReplyObject(reply);

/* Set a key using binary safe API */
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
printf("SET (binary API): %s\n", reply->str);
freeReplyObject(reply);

/* Try a GET and two INCR */
reply = redisCommand(c,"GET foo");
printf("GET foo: %s\n", reply->str);
freeReplyObject(reply);

reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* again ... */
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);

/* Create a list of numbers, from 0 to 9 */
reply = redisCommand(c,"DEL mylist");
freeReplyObject(reply);
for (j = 0; j < 10; j++) {
char buf[64];

snprintf(buf,64,"%u",j);
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
freeReplyObject(reply);
}

/* Let's check what we have inside the list */
reply = redisCommand(c,"LRANGE mylist 0 -1");
if (reply->type == REDIS_REPLY_ARRAY) {
for (j = 0; j < reply->elements; j++) {
printf("%u) %s\n", j, reply->element[j]->str);
}
}
freeReplyObject(reply);

/* Disconnects and frees the context */
redisFree(c);

return 0;
}

+ 0
- 91
俱乐部/Source/hiredis/examples/example.c Bestand weergeven

@@ -1,91 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <hiredis.h>

int main(int argc, char **argv) {
unsigned int j, isunix = 0;
redisContext *c;
redisReply *reply;
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";

if (argc > 2) {
if (*argv[2] == 'u' || *argv[2] == 'U') {
isunix = 1;
/* in this case, host is the path to the unix socket */
printf("Will connect to unix socket @%s\n", hostname);
}
}

int port = (argc > 2) ? atoi(argv[2]) : 6379;

struct timeval timeout = { 1, 500000 }; // 1.5 seconds
if (isunix) {
c = redisConnectUnixWithTimeout(hostname, timeout);
} else {
c = redisConnectWithTimeout(hostname, port, timeout);
}
if (c == NULL || c->err) {
if (c) {
printf("Connection error: %s\n", c->errstr);
redisFree(c);
} else {
printf("Connection error: can't allocate redis context\n");
}
exit(1);
}

/* PING server */
reply = redisCommand(c,"PING");
printf("PING: %s\n", reply->str);
freeReplyObject(reply);

/* Set a key */
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
printf("SET: %s\n", reply->str);
freeReplyObject(reply);

/* Set a key using binary safe API */
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
printf("SET (binary API): %s\n", reply->str);
freeReplyObject(reply);

/* Try a GET and two INCR */
reply = redisCommand(c,"GET foo");
printf("GET foo: %s\n", reply->str);
freeReplyObject(reply);

reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* again ... */
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);

/* Create a list of numbers, from 0 to 9 */
reply = redisCommand(c,"DEL mylist");
freeReplyObject(reply);
for (j = 0; j < 10; j++) {
char buf[64];

snprintf(buf,64,"%u",j);
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
freeReplyObject(reply);
}

/* Let's check what we have inside the list */
reply = redisCommand(c,"LRANGE mylist 0 -1");
if (reply->type == REDIS_REPLY_ARRAY) {
for (j = 0; j < reply->elements; j++) {
printf("%u) %s\n", j, reply->element[j]->str);
}
}
freeReplyObject(reply);

/* Disconnects and frees the context */
redisFree(c);

return 0;
}

+ 0
- 12
俱乐部/Source/hiredis/fmacros.h Bestand weergeven

@@ -1,12 +0,0 @@
#ifndef __HIREDIS_FMACRO_H
#define __HIREDIS_FMACRO_H

#define _XOPEN_SOURCE 600
#define _POSIX_C_SOURCE 200112L

#if defined(__APPLE__) && defined(__MACH__)
/* Enable TCP_KEEPALIVE */
#define _DARWIN_C_SOURCE
#endif

#endif

+ 0
- 1078
俱乐部/Source/hiredis/hiredis.c
Diff onderdrukt omdat het te groot bestand
Bestand weergeven


+ 0
- 298
俱乐部/Source/hiredis/hiredis.h Bestand weergeven

@@ -1,298 +0,0 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
* Jan-Erik Rediger <janerik at fnordig dot com>
*
* 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 Redis 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.
*/

#ifndef __HIREDIS_H
#define __HIREDIS_H
#include "read.h"
#include <stdarg.h> /* for va_list */
#ifndef _MSC_VER
#include <sys/time.h> /* for struct timeval */
#else
struct timeval; /* forward declaration */
#endif
#include <stdint.h> /* uintXX_t, etc */
#include "sds.h" /* for sds */
#include "alloc.h" /* for allocation wrappers */

#define HIREDIS_MAJOR 0
#define HIREDIS_MINOR 14
#define HIREDIS_PATCH 0
#define HIREDIS_SONAME 0.14

/* Connection type can be blocking or non-blocking and is set in the
* least significant bit of the flags field in redisContext. */
#define REDIS_BLOCK 0x1

/* Connection may be disconnected before being free'd. The second bit
* in the flags field is set when the context is connected. */
#define REDIS_CONNECTED 0x2

/* The async API might try to disconnect cleanly and flush the output
* buffer and read all subsequent replies before disconnecting.
* This flag means no new commands can come in and the connection
* should be terminated once all replies have been read. */
#define REDIS_DISCONNECTING 0x4

/* Flag specific to the async API which means that the context should be clean
* up as soon as possible. */
#define REDIS_FREEING 0x8

/* Flag that is set when an async callback is executed. */
#define REDIS_IN_CALLBACK 0x10

/* Flag that is set when the async context has one or more subscriptions. */
#define REDIS_SUBSCRIBED 0x20

/* Flag that is set when monitor mode is active */
#define REDIS_MONITORING 0x40

/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
#define REDIS_REUSEADDR 0x80

/**
* Flag that indicates the user does not want the context to
* be automatically freed upon error
*/
#define REDIS_NO_AUTO_FREE 0x200

#define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */

/* number of times we retry to connect in the case of EADDRNOTAVAIL and
* SO_REUSEADDR is being used. */
#define REDIS_CONNECT_RETRIES 10

#ifdef __cplusplus
extern "C" {
#endif

/* This is the reply object returned by redisCommand() */
typedef struct redisReply {
int type; /* REDIS_REPLY_* */
long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
double dval; /* The double when type is REDIS_REPLY_DOUBLE */
size_t len; /* Length of string */
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
and REDIS_REPLY_DOUBLE (in additional to dval). */
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;

redisReader *redisReaderCreate(void);

/* Function to free the reply objects hiredis returns by default. */
void freeReplyObject(void *reply);

/* Functions to format a command according to the protocol. */
int redisvFormatCommand(char **target, const char *format, va_list ap);
int redisFormatCommand(char **target, const char *format, ...);
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
void redisFreeCommand(char *cmd);
void redisFreeSdsCommand(sds cmd);

enum redisConnectionType {
REDIS_CONN_TCP,
REDIS_CONN_UNIX,
REDIS_CONN_USERFD
};

struct redisSsl;

#define REDIS_OPT_NONBLOCK 0x01
#define REDIS_OPT_REUSEADDR 0x02

/**
* Don't automatically free the async object on a connection failure,
* or other implicit conditions. Only free on an explicit call to disconnect() or free()
*/
#define REDIS_OPT_NOAUTOFREE 0x04

/* In Unix systems a file descriptor is a regular signed int, with -1
* representing an invalid descriptor. In Windows it is a SOCKET
* (32- or 64-bit unsigned integer depending on the architecture), where
* all bits set (~0) is INVALID_SOCKET. */
#ifndef _WIN32
typedef int redisFD;
#define REDIS_INVALID_FD -1
#else
#ifdef _WIN64
typedef unsigned long long redisFD; /* SOCKET = 64-bit UINT_PTR */
#else
typedef unsigned long redisFD; /* SOCKET = 32-bit UINT_PTR */
#endif
#define REDIS_INVALID_FD ((redisFD)(~0)) /* INVALID_SOCKET */
#endif

typedef struct {
/*
* the type of connection to use. This also indicates which
* `endpoint` member field to use
*/
int type;
/* bit field of REDIS_OPT_xxx */
int options;
/* timeout value. if NULL, no timeout is used */
const struct timeval *timeout;
union {
/** use this field for tcp/ip connections */
struct {
const char *source_addr;
const char *ip;
int port;
} tcp;
/** use this field for unix domain sockets */
const char *unix_socket;
/**
* use this field to have hiredis operate an already-open
* file descriptor */
redisFD fd;
} endpoint;
} redisOptions;

/**
* Helper macros to initialize options to their specified fields.
*/
#define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \
(opts)->type = REDIS_CONN_TCP; \
(opts)->endpoint.tcp.ip = ip_; \
(opts)->endpoint.tcp.port = port_;

#define REDIS_OPTIONS_SET_UNIX(opts, path) \
(opts)->type = REDIS_CONN_UNIX; \
(opts)->endpoint.unix_socket = path;

struct redisAsyncContext;
struct redisContext;

typedef struct redisContextFuncs {
void (*free_privdata)(void *);
void (*async_read)(struct redisAsyncContext *);
void (*async_write)(struct redisAsyncContext *);
int (*read)(struct redisContext *, char *, size_t);
int (*write)(struct redisContext *);
} redisContextFuncs;

/* Context for a connection to Redis */
typedef struct redisContext {
const redisContextFuncs *funcs; /* Function table */

int err; /* Error flags, 0 when there is no error */
char errstr[128]; /* String representation of error when applicable */
redisFD fd;
int flags;
char *obuf; /* Write buffer */
redisReader *reader; /* Protocol reader */

enum redisConnectionType connection_type;
struct timeval *timeout;

struct {
char *host;
char *source_addr;
int port;
} tcp;

struct {
char *path;
} unix_sock;

/* For non-blocking connect */
struct sockadr *saddr;
size_t addrlen;

/* Additional private data for hiredis addons such as SSL */
void *privdata;
} redisContext;

redisContext *redisConnectWithOptions(const redisOptions *options);
redisContext *redisConnect(const char *ip, int port);
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
redisContext *redisConnectNonBlock(const char *ip, int port);
redisContext *redisConnectBindNonBlock(const char *ip, int port,
const char *source_addr);
redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
const char *source_addr);
redisContext *redisConnectUnix(const char *path);
redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
redisContext *redisConnectUnixNonBlock(const char *path);
redisContext *redisConnectFd(redisFD fd);

/**
* Reconnect the given context using the saved information.
*
* This re-uses the exact same connect options as in the initial connection.
* host, ip (or path), timeout and bind address are reused,
* flags are used unmodified from the existing context.
*
* Returns REDIS_OK on successful connect or REDIS_ERR otherwise.
*/
int redisReconnect(redisContext *c);

int redisSetTimeout(redisContext *c, const struct timeval tv);
int redisEnableKeepAlive(redisContext *c);
void redisFree(redisContext *c);
redisFD redisFreeKeepFd(redisContext *c);
int redisBufferRead(redisContext *c);
int redisBufferWrite(redisContext *c, int *done);

/* In a blocking context, this function first checks if there are unconsumed
* replies to return and returns one if so. Otherwise, it flushes the output
* buffer to the socket and reads until it has a reply. In a non-blocking
* context, it will return unconsumed replies until there are no more. */
int redisGetReply(redisContext *c, void **reply);
int redisGetReplyFromReader(redisContext *c, void **reply);

/* Write a formatted command to the output buffer. Use these functions in blocking mode
* to get a pipeline of commands. */
int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len);

/* Write a command to the output buffer. Use these functions in blocking mode
* to get a pipeline of commands. */
int redisvAppendCommand(redisContext *c, const char *format, va_list ap);
int redisAppendCommand(redisContext *c, const char *format, ...);
int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

/* Issue a command to Redis. In a blocking context, it is identical to calling
* redisAppendCommand, followed by redisGetReply. The function will return
* NULL if there was an error in performing the request, otherwise it will
* return the reply. In a non-blocking context, it is identical to calling
* only redisAppendCommand and will always return NULL. */
void *redisvCommand(redisContext *c, const char *format, va_list ap);
void *redisCommand(redisContext *c, const char *format, ...);
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);

#ifdef __cplusplus
}
#endif

#endif

+ 0
- 11
俱乐部/Source/hiredis/hiredis.pc.in Bestand weergeven

@@ -1,11 +0,0 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
pkgincludedir=${includedir}/hiredis

Name: hiredis
Description: Minimalistic C client library for Redis.
Version: @PROJECT_VERSION@
Libs: -L${libdir} -lhiredis
Cflags: -I${pkgincludedir} -D_FILE_OFFSET_BITS=64

+ 0
- 53
俱乐部/Source/hiredis/hiredis_ssl.h Bestand weergeven

@@ -1,53 +0,0 @@

/*
* Copyright (c) 2019, Redis Labs
*
* 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 Redis 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.
*/

#ifndef __HIREDIS_SSL_H
#define __HIREDIS_SSL_H

/* This is the underlying struct for SSL in ssl.h, which is not included to
* keep build dependencies short here.
*/
struct ssl_st;

/**
* Secure the connection using SSL. This should be done before any command is
* executed on the connection.
*/
int redisSecureConnection(redisContext *c, const char *capath, const char *certpath,
const char *keypath, const char *servername);

/**
* Initiate SSL/TLS negotiation on a provided context.
*/

int redisInitiateSSL(redisContext *c, struct ssl_st *ssl);

#endif /* __HIREDIS_SSL_H */

+ 0
- 12
俱乐部/Source/hiredis/hiredis_ssl.pc.in Bestand weergeven

@@ -1,12 +0,0 @@
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
pkgincludedir=${includedir}/hiredis

Name: hiredis_ssl
Description: SSL Support for hiredis.
Version: @PROJECT_VERSION@
Requires: hiredis
Libs: -L${libdir} -lhiredis_ssl
Libs.private: -lssl -lcrypto

+ 0
- 571
俱乐部/Source/hiredis/net.c Bestand weergeven

@@ -1,571 +0,0 @@
/* Extracted from anet.c to work properly with Hiredis error reporting.
*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
* Jan-Erik Rediger <janerik at fnordig dot com>
*
* 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 Redis 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.
*/

#include "fmacros.h"
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

#include "net.h"
#include "sds.h"
#include "sockcompat.h"
#include "win32.h"

/* Defined in hiredis.c */
void __redisSetError(redisContext *c, int type, const char *str);

void redisNetClose(redisContext *c) {
if (c && c->fd != REDIS_INVALID_FD) {
close(c->fd);
c->fd = REDIS_INVALID_FD;
}
}

int redisNetRead(redisContext *c, char *buf, size_t bufcap) {
int nread = recv(c->fd, buf, bufcap, 0);
if (nread == -1) {
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
return 0;
} else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) {
/* especially in windows */
__redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout");
return -1;
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
} else if (nread == 0) {
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
return -1;
} else {
return nread;
}
}

int redisNetWrite(redisContext *c) {
int nwritten = send(c->fd, c->obuf, sdslen(c->obuf), 0);
if (nwritten < 0) {
if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {
/* Try again later */
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
}
return nwritten;
}

static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) {
int errorno = errno; /* snprintf() may change errno */
char buf[128] = { 0 };
size_t len = 0;

if (prefix != NULL)
len = snprintf(buf,sizeof(buf),"%s: ",prefix);
strerror_r(errorno, (char *)(buf + len), sizeof(buf) - len);
__redisSetError(c,type,buf);
}

static int redisSetReuseAddr(redisContext *c) {
int on = 1;
if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
redisNetClose(c);
return REDIS_ERR;
}
return REDIS_OK;
}

static int redisCreateSocket(redisContext *c, int type) {
redisFD s;
if ((s = socket(type, SOCK_STREAM, 0)) == REDIS_INVALID_FD) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
return REDIS_ERR;
}
c->fd = s;
if (type == AF_INET) {
if (redisSetReuseAddr(c) == REDIS_ERR) {
return REDIS_ERR;
}
}
return REDIS_OK;
}

static int redisSetBlocking(redisContext *c, int blocking) {
#ifndef _WIN32
int flags;

/* Set the socket nonblocking.
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. */
if ((flags = fcntl(c->fd, F_GETFL)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)");
redisNetClose(c);
return REDIS_ERR;
}

if (blocking)
flags &= ~O_NONBLOCK;
else
flags |= O_NONBLOCK;

if (fcntl(c->fd, F_SETFL, flags) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)");
redisNetClose(c);
return REDIS_ERR;
}
#else
u_long mode = blocking ? 0 : 1;
if (ioctl(c->fd, FIONBIO, &mode) == -1) {
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "ioctl(FIONBIO)");
redisNetClose(c);
return REDIS_ERR;
}
#endif /* _WIN32 */
return REDIS_OK;
}

int redisKeepAlive(redisContext *c, int interval) {
int val = 1;
redisFD fd = c->fd;

if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
return REDIS_ERR;
}

val = interval;

#if defined(__APPLE__) && defined(__MACH__)
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) {
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
return REDIS_ERR;
}
#else
#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
return REDIS_ERR;
}

val = interval/3;
if (val == 0) val = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
return REDIS_ERR;
}

val = 3;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
__redisSetError(c,REDIS_ERR_OTHER,strerror(errno));
return REDIS_ERR;
}
#endif
#endif

return REDIS_OK;
}

static int redisSetTcpNoDelay(redisContext *c) {
int yes = 1;
if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)");
redisNetClose(c);
return REDIS_ERR;
}
return REDIS_OK;
}

#define __MAX_MSEC (((LONG_MAX) - 999) / 1000)

static int redisContextTimeoutMsec(redisContext *c, long *result)
{
const struct timeval *timeout = c->timeout;
long msec = -1;

/* Only use timeout when not NULL. */
if (timeout != NULL) {
if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
*result = msec;
return REDIS_ERR;
}

msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000);

if (msec < 0 || msec > INT_MAX) {
msec = INT_MAX;
}
}

*result = msec;
return REDIS_OK;
}

static int redisContextWaitReady(redisContext *c, long msec) {
struct pollfd wfd[1];

wfd[0].fd = c->fd;
wfd[0].events = POLLOUT;

if (errno == EINPROGRESS) {
int res;

if ((res = poll(wfd, 1, msec)) == -1) {
__redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
redisNetClose(c);
return REDIS_ERR;
} else if (res == 0) {
errno = ETIMEDOUT;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
redisNetClose(c);
return REDIS_ERR;
}

if (redisCheckConnectDone(c, &res) != REDIS_OK || res == 0) {
redisCheckSocketError(c);
return REDIS_ERR;
}

return REDIS_OK;
}

__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
redisNetClose(c);
return REDIS_ERR;
}

int redisCheckConnectDone(redisContext *c, int *completed) {
int rc = connect(c->fd, (const struct sockaddr *)c->saddr, c->addrlen);
if (rc == 0) {
*completed = 1;
return REDIS_OK;
}
switch (errno) {
case EISCONN:
*completed = 1;
return REDIS_OK;
case EALREADY:
case EINPROGRESS:
case EWOULDBLOCK:
*completed = 0;
return REDIS_OK;
default:
return REDIS_ERR;
}
}

int redisCheckSocketError(redisContext *c) {
int err = 0, errno_saved = errno;
socklen_t errlen = sizeof(err);

if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)");
return REDIS_ERR;
}

if (err == 0) {
err = errno_saved;
}

if (err) {
errno = err;
__redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
return REDIS_ERR;
}

return REDIS_OK;
}

int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
const void *to_ptr = &tv;
size_t to_sz = sizeof(tv);
#ifdef _WIN32
DWORD timeout_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
to_ptr = &timeout_msec;
to_sz = sizeof(timeout_msec);
#endif
if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
return REDIS_ERR;
}
if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) {
__redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)");
return REDIS_ERR;
}
return REDIS_OK;
}

static int _redisContextConnectTcp(redisContext *c, const char *addr, int port,
const struct timeval *timeout,
const char *source_addr) {
redisFD s;
int rv, n;
char _port[6]; /* strlen("65535"); */
struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
int blocking = (c->flags & REDIS_BLOCK);
int reuseaddr = (c->flags & REDIS_REUSEADDR);
int reuses = 0;
long timeout_msec = -1;

servinfo = NULL;
c->connection_type = REDIS_CONN_TCP;
c->tcp.port = port;

/* We need to take possession of the passed parameters
* to make them reusable for a reconnect.
* We also carefully check we don't free data we already own,
* as in the case of the reconnect method.
*
* This is a bit ugly, but atleast it works and doesn't leak memory.
**/
if (c->tcp.host != addr) {
free(c->tcp.host);

c->tcp.host = hi_strdup(addr);
}

if (timeout) {
if (c->timeout != timeout) {
if (c->timeout == NULL)
c->timeout = hi_malloc(sizeof(struct timeval));

memcpy(c->timeout, timeout, sizeof(struct timeval));
}
} else {
free(c->timeout);
c->timeout = NULL;
}

if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) {
__redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified");
goto error;
}

if (source_addr == NULL) {
free(c->tcp.source_addr);
c->tcp.source_addr = NULL;
} else if (c->tcp.source_addr != source_addr) {
free(c->tcp.source_addr);
c->tcp.source_addr = hi_strdup(source_addr);
}

snprintf(_port, 6, "%d", port);
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;

/* Try with IPv6 if no IPv4 address was found. We do it in this order since
* in a Redis client you can't afford to test if you have IPv6 connectivity
* as this would add latency to every connect. Otherwise a more sensible
* route could be: Use IPv6 if both addresses are available and there is IPv6
* connectivity. */
if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) {
hints.ai_family = AF_INET6;
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
__redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
return REDIS_ERR;
}
}
for (p = servinfo; p != NULL; p = p->ai_next) {
addrretry:
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == REDIS_INVALID_FD)
continue;

c->fd = s;
if (redisSetBlocking(c,0) != REDIS_OK)
goto error;
if (c->tcp.source_addr) {
int bound = 0;
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) {
char buf[128];
snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv));
__redisSetError(c,REDIS_ERR_OTHER,buf);
goto error;
}

if (reuseaddr) {
n = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
sizeof(n)) < 0) {
freeaddrinfo(bservinfo);
goto error;
}
}

for (b = bservinfo; b != NULL; b = b->ai_next) {
if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
bound = 1;
break;
}
}
freeaddrinfo(bservinfo);
if (!bound) {
char buf[128];
snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno));
__redisSetError(c,REDIS_ERR_OTHER,buf);
goto error;
}
}

/* For repeat connection */
free(c->saddr);
c->saddr = hi_malloc(p->ai_addrlen);
memcpy(c->saddr, p->ai_addr, p->ai_addrlen);
c->addrlen = p->ai_addrlen;

if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
if (errno == EHOSTUNREACH) {
redisNetClose(c);
continue;
} else if (errno == EINPROGRESS) {
if (blocking) {
goto wait_for_ready;
}
/* This is ok.
* Note that even when it's in blocking mode, we unset blocking
* for `connect()`
*/
} else if (errno == EADDRNOTAVAIL && reuseaddr) {
if (++reuses >= REDIS_CONNECT_RETRIES) {
goto error;
} else {
redisNetClose(c);
goto addrretry;
}
} else {
wait_for_ready:
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
goto error;
}
}
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
goto error;
if (redisSetTcpNoDelay(c) != REDIS_OK)
goto error;

c->flags |= REDIS_CONNECTED;
rv = REDIS_OK;
goto end;
}
if (p == NULL) {
char buf[128];
snprintf(buf,sizeof(buf),"Can't create socket: %s",strerror(errno));
__redisSetError(c,REDIS_ERR_OTHER,buf);
goto error;
}

error:
rv = REDIS_ERR;
end:
if(servinfo) {
freeaddrinfo(servinfo);
}

return rv; // Need to return REDIS_OK if alright
}

int redisContextConnectTcp(redisContext *c, const char *addr, int port,
const struct timeval *timeout) {
return _redisContextConnectTcp(c, addr, port, timeout, NULL);
}

int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
const struct timeval *timeout,
const char *source_addr) {
return _redisContextConnectTcp(c, addr, port, timeout, source_addr);
}

int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) {
#ifndef _WIN32
int blocking = (c->flags & REDIS_BLOCK);
struct sockaddr_un *sa;
long timeout_msec = -1;

if (redisCreateSocket(c,AF_UNIX) < 0)
return REDIS_ERR;
if (redisSetBlocking(c,0) != REDIS_OK)
return REDIS_ERR;

c->connection_type = REDIS_CONN_UNIX;
if (c->unix_sock.path != path)
c->unix_sock.path = hi_strdup(path);

if (timeout) {
if (c->timeout != timeout) {
if (c->timeout == NULL)
c->timeout = hi_malloc(sizeof(struct timeval));

memcpy(c->timeout, timeout, sizeof(struct timeval));
}
} else {
free(c->timeout);
c->timeout = NULL;
}

if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK)
return REDIS_ERR;

sa = (struct sockaddr_un*)(c->saddr = hi_malloc(sizeof(struct sockaddr_un)));
c->addrlen = sizeof(struct sockaddr_un);
sa->sun_family = AF_UNIX;
strncpy(sa->sun_path, path, sizeof(sa->sun_path) - 1);
if (connect(c->fd, (struct sockaddr*)sa, sizeof(*sa)) == -1) {
if (errno == EINPROGRESS && !blocking) {
/* This is ok. */
} else {
if (redisContextWaitReady(c,timeout_msec) != REDIS_OK)
return REDIS_ERR;
}
}

/* Reset socket to be blocking after connect(2). */
if (blocking && redisSetBlocking(c,1) != REDIS_OK)
return REDIS_ERR;

c->flags |= REDIS_CONNECTED;
return REDIS_OK;
#else
/* We currently do not support Unix sockets for Windows. */
/* TODO(m): https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */
errno = EPROTONOSUPPORT;
return REDIS_ERR;
#endif /* _WIN32 */
}

+ 0
- 54
俱乐部/Source/hiredis/net.h Bestand weergeven

@@ -1,54 +0,0 @@
/* Extracted from anet.c to work properly with Hiredis error reporting.
*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
* Jan-Erik Rediger <janerik at fnordig dot com>
*
* 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 Redis 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.
*/

#ifndef __NET_H
#define __NET_H

#include "hiredis.h"

void redisNetClose(redisContext *c);
int redisNetRead(redisContext *c, char *buf, size_t bufcap);
int redisNetWrite(redisContext *c);

int redisCheckSocketError(redisContext *c);
int redisContextSetTimeout(redisContext *c, const struct timeval tv);
int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
const struct timeval *timeout,
const char *source_addr);
int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout);
int redisKeepAlive(redisContext *c, int interval);
int redisCheckConnectDone(redisContext *c, int *completed);

#endif

+ 0
- 669
俱乐部/Source/hiredis/read.c Bestand weergeven

@@ -1,669 +0,0 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/

#include "fmacros.h"
#include <string.h>
#include <stdlib.h>
#ifndef _MSC_VER
#include <unistd.h>
#include <strings.h>
#endif
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>

#include "read.h"
#include "sds.h"
#include "win32.h"

static void __redisReaderSetError(redisReader *r, int type, const char *str) {
size_t len;

if (r->reply != NULL && r->fn && r->fn->freeObject) {
r->fn->freeObject(r->reply);
r->reply = NULL;
}

/* Clear input buffer on errors. */
sdsfree(r->buf);
r->buf = NULL;
r->pos = r->len = 0;

/* Reset task stack. */
r->ridx = -1;

/* Set error. */
r->err = type;
len = strlen(str);
len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
memcpy(r->errstr,str,len);
r->errstr[len] = '\0';
}

static size_t chrtos(char *buf, size_t size, char byte) {
size_t len = 0;

switch(byte) {
case '\\':
case '"':
len = snprintf(buf,size,"\"\\%c\"",byte);
break;
case '\n': len = snprintf(buf,size,"\"\\n\""); break;
case '\r': len = snprintf(buf,size,"\"\\r\""); break;
case '\t': len = snprintf(buf,size,"\"\\t\""); break;
case '\a': len = snprintf(buf,size,"\"\\a\""); break;
case '\b': len = snprintf(buf,size,"\"\\b\""); break;
default:
if (isprint(byte))
len = snprintf(buf,size,"\"%c\"",byte);
else
len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
break;
}

return len;
}

static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
char cbuf[8], sbuf[128];

chrtos(cbuf,sizeof(cbuf),byte);
snprintf(sbuf,sizeof(sbuf),
"Protocol error, got %s as reply type byte", cbuf);
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
}

static void __redisReaderSetErrorOOM(redisReader *r) {
__redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
}

static char *readBytes(redisReader *r, unsigned int bytes) {
char *p;
if (r->len-r->pos >= bytes) {
p = r->buf+r->pos;
r->pos += bytes;
return p;
}
return NULL;
}

/* Find pointer to \r\n. */
static char *seekNewline(char *s, size_t len) {
int pos = 0;
int _len = len-1;

/* Position should be < len-1 because the character at "pos" should be
* followed by a \n. Note that strchr cannot be used because it doesn't
* allow to search a limited length and the buffer that is being searched
* might not have a trailing NULL character. */
while (pos < _len) {
while(pos < _len && s[pos] != '\r') pos++;
if (pos==_len) {
/* Not found. */
return NULL;
} else {
if (s[pos+1] == '\n') {
/* Found. */
return s+pos;
} else {
/* Continue searching. */
pos++;
}
}
}
return NULL;
}

/* Convert a string into a long long. Returns REDIS_OK if the string could be
* parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value
* will be set to the parsed value when appropriate.
*
* Note that this function demands that the string strictly represents
* a long long: no spaces or other characters before or after the string
* representing the number are accepted, nor zeroes at the start if not
* for the string "0" representing the zero number.
*
* Because of its strictness, it is safe to use this function to check if
* you can convert a string into a long long, and obtain back the string
* from the number without any loss in the string representation. */
static int string2ll(const char *s, size_t slen, long long *value) {
const char *p = s;
size_t plen = 0;
int negative = 0;
unsigned long long v;

if (plen == slen)
return REDIS_ERR;

/* Special case: first and only digit is 0. */
if (slen == 1 && p[0] == '0') {
if (value != NULL) *value = 0;
return REDIS_OK;
}

if (p[0] == '-') {
negative = 1;
p++; plen++;

/* Abort on only a negative sign. */
if (plen == slen)
return REDIS_ERR;
}

/* First digit should be 1-9, otherwise the string should just be 0. */
if (p[0] >= '1' && p[0] <= '9') {
v = p[0]-'0';
p++; plen++;
} else if (p[0] == '0' && slen == 1) {
*value = 0;
return REDIS_OK;
} else {
return REDIS_ERR;
}

while (plen < slen && p[0] >= '0' && p[0] <= '9') {
if (v > (ULLONG_MAX / 10)) /* Overflow. */
return REDIS_ERR;
v *= 10;

if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
return REDIS_ERR;
v += p[0]-'0';

p++; plen++;
}

/* Return if not all bytes were used. */
if (plen < slen)
return REDIS_ERR;

if (negative) {
if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
return REDIS_ERR;
if (value != NULL) *value = -v;
} else {
if (v > LLONG_MAX) /* Overflow. */
return REDIS_ERR;
if (value != NULL) *value = v;
}
return REDIS_OK;
}

static char *readLine(redisReader *r, int *_len) {
char *p, *s;
int len;

p = r->buf+r->pos;
s = seekNewline(p,(r->len-r->pos));
if (s != NULL) {
len = s-(r->buf+r->pos);
r->pos += len+2; /* skip \r\n */
if (_len) *_len = len;
return p;
}
return NULL;
}

static void moveToNextTask(redisReader *r) {
redisReadTask *cur, *prv;
while (r->ridx >= 0) {
/* Return a.s.a.p. when the stack is now empty. */
if (r->ridx == 0) {
r->ridx--;
return;
}

cur = &(r->rstack[r->ridx]);
prv = &(r->rstack[r->ridx-1]);
assert(prv->type == REDIS_REPLY_ARRAY ||
prv->type == REDIS_REPLY_MAP ||
prv->type == REDIS_REPLY_SET);
if (cur->idx == prv->elements-1) {
r->ridx--;
} else {
/* Reset the type because the next item can be anything */
assert(cur->idx < prv->elements);
cur->type = -1;
cur->elements = -1;
cur->idx++;
return;
}
}
}

static int processLineItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
int len;

if ((p = readLine(r,&len)) != NULL) {
if (cur->type == REDIS_REPLY_INTEGER) {
if (r->fn && r->fn->createInteger) {
long long v;
if (string2ll(p, len, &v) == REDIS_ERR) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Bad integer value");
return REDIS_ERR;
}
obj = r->fn->createInteger(cur,v);
} else {
obj = (void*)REDIS_REPLY_INTEGER;
}
} else if (cur->type == REDIS_REPLY_DOUBLE) {
if (r->fn && r->fn->createDouble) {
char buf[326], *eptr;
double d;

if ((size_t)len >= sizeof(buf)) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Double value is too large");
return REDIS_ERR;
}

memcpy(buf,p,len);
buf[len] = '\0';

if (strcasecmp(buf,",inf") == 0) {
d = INFINITY; /* Positive infinite. */
} else if (strcasecmp(buf,",-inf") == 0) {
d = -INFINITY; /* Negative infinite. */
} else {
d = strtod((char*)buf,&eptr);
if (buf[0] == '\0' || eptr[0] != '\0' || isnan(d)) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Bad double value");
return REDIS_ERR;
}
}
obj = r->fn->createDouble(cur,d,buf,len);
} else {
obj = (void*)REDIS_REPLY_DOUBLE;
}
} else if (cur->type == REDIS_REPLY_NIL) {
if (r->fn && r->fn->createNil)
obj = r->fn->createNil(cur);
else
obj = (void*)REDIS_REPLY_NIL;
} else if (cur->type == REDIS_REPLY_BOOL) {
int bval = p[0] == 't' || p[0] == 'T';
if (r->fn && r->fn->createBool)
obj = r->fn->createBool(cur,bval);
else
obj = (void*)REDIS_REPLY_BOOL;
} else {
/* Type will be error or status. */
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,p,len);
else
obj = (void*)(size_t)(cur->type);
}

if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}

/* Set reply if this is the root object. */
if (r->ridx == 0) r->reply = obj;
moveToNextTask(r);
return REDIS_OK;
}

return REDIS_ERR;
}

static int processBulkItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj = NULL;
char *p, *s;
long long len;
unsigned long bytelen;
int success = 0;

p = r->buf+r->pos;
s = seekNewline(p,r->len-r->pos);
if (s != NULL) {
p = r->buf+r->pos;
bytelen = s-(r->buf+r->pos)+2; /* include \r\n */

if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Bad bulk string length");
return REDIS_ERR;
}

if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Bulk string length out of range");
return REDIS_ERR;
}

if (len == -1) {
/* The nil object can always be created. */
if (r->fn && r->fn->createNil)
obj = r->fn->createNil(cur);
else
obj = (void*)REDIS_REPLY_NIL;
success = 1;
} else {
/* Only continue when the buffer contains the entire bulk item. */
bytelen += len+2; /* include \r\n */
if (r->pos+bytelen <= r->len) {
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,s+2,len);
else
obj = (void*)REDIS_REPLY_STRING;
success = 1;
}
}

/* Proceed when obj was created. */
if (success) {
if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}

r->pos += bytelen;

/* Set reply if this is the root object. */
if (r->ridx == 0) r->reply = obj;
moveToNextTask(r);
return REDIS_OK;
}
}

return REDIS_ERR;
}

/* Process the array, map and set types. */
static int processAggregateItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
long long elements;
int root = 0, len;

/* Set error for nested multi bulks with depth > 7 */
if (r->ridx == 8) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"No support for nested multi bulk replies with depth > 7");
return REDIS_ERR;
}

if ((p = readLine(r,&len)) != NULL) {
if (string2ll(p, len, &elements) == REDIS_ERR) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Bad multi-bulk length");
return REDIS_ERR;
}

root = (r->ridx == 0);

if (elements < -1 || (LLONG_MAX > SIZE_MAX && elements > SIZE_MAX)) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Multi-bulk length out of range");
return REDIS_ERR;
}

if (elements == -1) {
if (r->fn && r->fn->createNil)
obj = r->fn->createNil(cur);
else
obj = (void*)REDIS_REPLY_NIL;

if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}

moveToNextTask(r);
} else {
if (cur->type == REDIS_REPLY_MAP) elements *= 2;

if (r->fn && r->fn->createArray)
obj = r->fn->createArray(cur,elements);
else
obj = (void*)(long)cur->type;

if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}

/* Modify task stack when there are more than 0 elements. */
if (elements > 0) {
cur->elements = elements;
cur->obj = obj;
r->ridx++;
r->rstack[r->ridx].type = -1;
r->rstack[r->ridx].elements = -1;
r->rstack[r->ridx].idx = 0;
r->rstack[r->ridx].obj = NULL;
r->rstack[r->ridx].parent = cur;
r->rstack[r->ridx].privdata = r->privdata;
} else {
moveToNextTask(r);
}
}

/* Set reply if this is the root object. */
if (root) r->reply = obj;
return REDIS_OK;
}

return REDIS_ERR;
}

static int processItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
char *p;

/* check if we need to read type */
if (cur->type < 0) {
if ((p = readBytes(r,1)) != NULL) {
switch (p[0]) {
case '-':
cur->type = REDIS_REPLY_ERROR;
break;
case '+':
cur->type = REDIS_REPLY_STATUS;
break;
case ':':
cur->type = REDIS_REPLY_INTEGER;
break;
case ',':
cur->type = REDIS_REPLY_DOUBLE;
break;
case '_':
cur->type = REDIS_REPLY_NIL;
break;
case '$':
cur->type = REDIS_REPLY_STRING;
break;
case '*':
cur->type = REDIS_REPLY_ARRAY;
break;
case '%':
cur->type = REDIS_REPLY_MAP;
break;
case '~':
cur->type = REDIS_REPLY_SET;
break;
case '#':
cur->type = REDIS_REPLY_BOOL;
break;
default:
__redisReaderSetErrorProtocolByte(r,*p);
return REDIS_ERR;
}
} else {
/* could not consume 1 byte */
return REDIS_ERR;
}
}

/* process typed item */
switch(cur->type) {
case REDIS_REPLY_ERROR:
case REDIS_REPLY_STATUS:
case REDIS_REPLY_INTEGER:
case REDIS_REPLY_DOUBLE:
case REDIS_REPLY_NIL:
case REDIS_REPLY_BOOL:
return processLineItem(r);
case REDIS_REPLY_STRING:
return processBulkItem(r);
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
case REDIS_REPLY_SET:
return processAggregateItem(r);
default:
assert(NULL);
return REDIS_ERR; /* Avoid warning. */
}
}

redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
redisReader *r;

r = calloc(1,sizeof(redisReader));
if (r == NULL)
return NULL;

r->fn = fn;
r->buf = sdsempty();
r->maxbuf = REDIS_READER_MAX_BUF;
if (r->buf == NULL) {
free(r);
return NULL;
}

r->ridx = -1;
return r;
}

void redisReaderFree(redisReader *r) {
if (r == NULL)
return;
if (r->reply != NULL && r->fn && r->fn->freeObject)
r->fn->freeObject(r->reply);
sdsfree(r->buf);
free(r);
}

int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
sds newbuf;

/* Return early when this reader is in an erroneous state. */
if (r->err)
return REDIS_ERR;

/* Copy the provided buffer. */
if (buf != NULL && len >= 1) {
/* Destroy internal buffer when it is empty and is quite large. */
if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
sdsfree(r->buf);
r->buf = sdsempty();
r->pos = 0;

/* r->buf should not be NULL since we just free'd a larger one. */
assert(r->buf != NULL);
}

newbuf = sdscatlen(r->buf,buf,len);
if (newbuf == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}

r->buf = newbuf;
r->len = sdslen(r->buf);
}

return REDIS_OK;
}

int redisReaderGetReply(redisReader *r, void **reply) {
/* Default target pointer to NULL. */
if (reply != NULL)
*reply = NULL;

/* Return early when this reader is in an erroneous state. */
if (r->err)
return REDIS_ERR;

/* When the buffer is empty, there will never be a reply. */
if (r->len == 0)
return REDIS_OK;

/* Set first item to process when the stack is empty. */
if (r->ridx == -1) {
r->rstack[0].type = -1;
r->rstack[0].elements = -1;
r->rstack[0].idx = -1;
r->rstack[0].obj = NULL;
r->rstack[0].parent = NULL;
r->rstack[0].privdata = r->privdata;
r->ridx = 0;
}

/* Process items in reply. */
while (r->ridx >= 0)
if (processItem(r) != REDIS_OK)
break;

/* Return ASAP when an error occurred. */
if (r->err)
return REDIS_ERR;

/* Discard part of the buffer when we've consumed at least 1k, to avoid
* doing unnecessary calls to memmove() in sds.c. */
if (r->pos >= 1024) {
sdsrange(r->buf,r->pos,-1);
r->pos = 0;
r->len = sdslen(r->buf);
}

/* Emit a reply when there is one. */
if (r->ridx == -1) {
if (reply != NULL) {
*reply = r->reply;
} else if (r->reply != NULL && r->fn && r->fn->freeObject) {
r->fn->freeObject(r->reply);
}
r->reply = NULL;
}
return REDIS_OK;
}

+ 0
- 122
俱乐部/Source/hiredis/read.h Bestand weergeven

@@ -1,122 +0,0 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* 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 Redis 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.
*/


#ifndef __HIREDIS_READ_H
#define __HIREDIS_READ_H
#include <stdio.h> /* for size_t */

#define REDIS_ERR -1
#define REDIS_OK 0

/* When an error occurs, the err flag in a context is set to hold the type of
* error that occurred. REDIS_ERR_IO means there was an I/O error and you
* should use the "errno" variable to find out what is wrong.
* For other values, the "errstr" field will hold a description. */
#define REDIS_ERR_IO 1 /* Error in read or write */
#define REDIS_ERR_EOF 3 /* End of file */
#define REDIS_ERR_PROTOCOL 4 /* Protocol error */
#define REDIS_ERR_OOM 5 /* Out of memory */
#define REDIS_ERR_TIMEOUT 6 /* Timed out */
#define REDIS_ERR_OTHER 2 /* Everything else... */

#define REDIS_REPLY_STRING 1
#define REDIS_REPLY_ARRAY 2
#define REDIS_REPLY_INTEGER 3
#define REDIS_REPLY_NIL 4
#define REDIS_REPLY_STATUS 5
#define REDIS_REPLY_ERROR 6
#define REDIS_REPLY_DOUBLE 7
#define REDIS_REPLY_BOOL 8
#define REDIS_REPLY_VERB 9
#define REDIS_REPLY_MAP 9
#define REDIS_REPLY_SET 10
#define REDIS_REPLY_ATTR 11
#define REDIS_REPLY_PUSH 12
#define REDIS_REPLY_BIGNUM 13

#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */

#ifdef __cplusplus
extern "C" {
#endif

typedef struct redisReadTask {
int type;
int elements; /* number of elements in multibulk container */
int idx; /* index in parent (array) object */
void *obj; /* holds user-generated value for a read task */
struct redisReadTask *parent; /* parent task */
void *privdata; /* user-settable arbitrary field */
} redisReadTask;

typedef struct redisReplyObjectFunctions {
void *(*createString)(const redisReadTask*, char*, size_t);
void *(*createArray)(const redisReadTask*, size_t);
void *(*createInteger)(const redisReadTask*, long long);
void *(*createDouble)(const redisReadTask*, double, char*, size_t);
void *(*createNil)(const redisReadTask*);
void *(*createBool)(const redisReadTask*, int);
void (*freeObject)(void*);
} redisReplyObjectFunctions;

typedef struct redisReader {
int err; /* Error flags, 0 when there is no error */
char errstr[128]; /* String representation of error when applicable */

char *buf; /* Read buffer */
size_t pos; /* Buffer cursor */
size_t len; /* Buffer length */
size_t maxbuf; /* Max length of unused buffer */

redisReadTask rstack[9];
int ridx; /* Index of current read task */
void *reply; /* Temporary reply pointer */

redisReplyObjectFunctions *fn;
void *privdata;
} redisReader;

/* Public API for the protocol parser. */
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn);
void redisReaderFree(redisReader *r);
int redisReaderFeed(redisReader *r, const char *buf, size_t len);
int redisReaderGetReply(redisReader *r, void **reply);

#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p))
#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply)
#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr)

#ifdef __cplusplus
}
#endif

#endif

+ 0
- 1291
俱乐部/Source/hiredis/sds.c
Diff onderdrukt omdat het te groot bestand
Bestand weergeven


+ 0
- 276
俱乐部/Source/hiredis/sds.h Bestand weergeven

@@ -1,276 +0,0 @@
/* SDSLib 2.0 -- A C dynamic strings library
*
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2015, Oran Agra
* Copyright (c) 2015, Redis Labs, 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 Redis 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.
*/

#ifndef __SDS_H
#define __SDS_H

#define SDS_MAX_PREALLOC (1024*1024)
#ifdef _MSC_VER
#define __attribute__(x)
#endif

#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>

typedef char *sds;

/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};

#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)

static inline size_t sdslen(const sds s) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:
return SDS_HDR(8,s)->len;
case SDS_TYPE_16:
return SDS_HDR(16,s)->len;
case SDS_TYPE_32:
return SDS_HDR(32,s)->len;
case SDS_TYPE_64:
return SDS_HDR(64,s)->len;
}
return 0;
}

static inline size_t sdsavail(const sds s) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5: {
return 0;
}
case SDS_TYPE_8: {
SDS_HDR_VAR(8,s);
return sh->alloc - sh->len;
}
case SDS_TYPE_16: {
SDS_HDR_VAR(16,s);
return sh->alloc - sh->len;
}
case SDS_TYPE_32: {
SDS_HDR_VAR(32,s);
return sh->alloc - sh->len;
}
case SDS_TYPE_64: {
SDS_HDR_VAR(64,s);
return sh->alloc - sh->len;
}
}
return 0;
}

static inline void sdssetlen(sds s, size_t newlen) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));
}
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->len = (uint8_t)newlen;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->len = (uint16_t)newlen;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->len = (uint32_t)newlen;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->len = (uint64_t)newlen;
break;
}
}

static inline void sdsinclen(sds s, size_t inc) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
unsigned char newlen = SDS_TYPE_5_LEN(flags)+(unsigned char)inc;
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
}
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->len += (uint8_t)inc;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->len += (uint16_t)inc;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->len += (uint32_t)inc;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->len += (uint64_t)inc;
break;
}
}

/* sdsalloc() = sdsavail() + sdslen() */
static inline size_t sdsalloc(const sds s) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:
return SDS_HDR(8,s)->alloc;
case SDS_TYPE_16:
return SDS_HDR(16,s)->alloc;
case SDS_TYPE_32:
return SDS_HDR(32,s)->alloc;
case SDS_TYPE_64:
return SDS_HDR(64,s)->alloc;
}
return 0;
}

static inline void sdssetalloc(sds s, size_t newlen) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
/* Nothing to do, this type has no total allocation info. */
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->alloc = (uint8_t)newlen;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->alloc = (uint16_t)newlen;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->alloc = (uint32_t)newlen;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->alloc = (uint64_t)newlen;
break;
}
}

sds sdsnewlen(const void *init, size_t initlen);
sds sdsnew(const char *init);
sds sdsempty(void);
sds sdsdup(const sds s);
void sdsfree(sds s);
sds sdsgrowzero(sds s, size_t len);
sds sdscatlen(sds s, const void *t, size_t len);
sds sdscat(sds s, const char *t);
sds sdscatsds(sds s, const sds t);
sds sdscpylen(sds s, const char *t, size_t len);
sds sdscpy(sds s, const char *t);

sds sdscatvprintf(sds s, const char *fmt, va_list ap);
#ifdef __GNUC__
sds sdscatprintf(sds s, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#else
sds sdscatprintf(sds s, const char *fmt, ...);
#endif

sds sdscatfmt(sds s, char const *fmt, ...);
sds sdstrim(sds s, const char *cset);
void sdsrange(sds s, int start, int end);
void sdsupdatelen(sds s);
void sdsclear(sds s);
int sdscmp(const sds s1, const sds s2);
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
void sdsfreesplitres(sds *tokens, int count);
void sdstolower(sds s);
void sdstoupper(sds s);
sds sdsfromlonglong(long long value);
sds sdscatrepr(sds s, const char *p, size_t len);
sds *sdssplitargs(const char *line, int *argc);
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
sds sdsjoin(char **argv, int argc, char *sep);
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);

/* Low level functions exposed to the user API */
sds sdsMakeRoomFor(sds s, size_t addlen);
void sdsIncrLen(sds s, int incr);
sds sdsRemoveFreeSpace(sds s);
size_t sdsAllocSize(sds s);
void *sdsAllocPtr(sds s);

/* Export the allocator used by SDS to the program using SDS.
* Sometimes the program SDS is linked to, may use a different set of
* allocators, but may want to allocate or free things that SDS will
* respectively free or allocate. */
void *sds_malloc(size_t size);
void *sds_realloc(void *ptr, size_t size);
void sds_free(void *ptr);

#ifdef REDIS_TEST
int sdsTest(int argc, char *argv[]);
#endif

#endif

+ 0
- 42
俱乐部/Source/hiredis/sdsalloc.h Bestand weergeven

@@ -1,42 +0,0 @@
/* SDSLib 2.0 -- A C dynamic strings library
*
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2015, Oran Agra
* Copyright (c) 2015, Redis Labs, 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 Redis 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.
*/

/* SDS allocator selection.
*
* This file is used in order to change the SDS allocator at compile time.
* Just define the following defines to what you want to use. Also add
* the include of your alternate allocator if needed (not needed in order
* to use the default libc allocator). */

#define s_malloc malloc
#define s_realloc realloc
#define s_free free

+ 0
- 248
俱乐部/Source/hiredis/sockcompat.c Bestand weergeven

@@ -1,248 +0,0 @@
/*
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
*
* 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 Redis 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.
*/

#define REDIS_SOCKCOMPAT_IMPLEMENTATION
#include "sockcompat.h"

#ifdef _WIN32
static int _wsaErrorToErrno(int err) {
switch (err) {
case WSAEWOULDBLOCK:
return EWOULDBLOCK;
case WSAEINPROGRESS:
return EINPROGRESS;
case WSAEALREADY:
return EALREADY;
case WSAENOTSOCK:
return ENOTSOCK;
case WSAEDESTADDRREQ:
return EDESTADDRREQ;
case WSAEMSGSIZE:
return EMSGSIZE;
case WSAEPROTOTYPE:
return EPROTOTYPE;
case WSAENOPROTOOPT:
return ENOPROTOOPT;
case WSAEPROTONOSUPPORT:
return EPROTONOSUPPORT;
case WSAEOPNOTSUPP:
return EOPNOTSUPP;
case WSAEAFNOSUPPORT:
return EAFNOSUPPORT;
case WSAEADDRINUSE:
return EADDRINUSE;
case WSAEADDRNOTAVAIL:
return EADDRNOTAVAIL;
case WSAENETDOWN:
return ENETDOWN;
case WSAENETUNREACH:
return ENETUNREACH;
case WSAENETRESET:
return ENETRESET;
case WSAECONNABORTED:
return ECONNABORTED;
case WSAECONNRESET:
return ECONNRESET;
case WSAENOBUFS:
return ENOBUFS;
case WSAEISCONN:
return EISCONN;
case WSAENOTCONN:
return ENOTCONN;
case WSAETIMEDOUT:
return ETIMEDOUT;
case WSAECONNREFUSED:
return ECONNREFUSED;
case WSAELOOP:
return ELOOP;
case WSAENAMETOOLONG:
return ENAMETOOLONG;
case WSAEHOSTUNREACH:
return EHOSTUNREACH;
case WSAENOTEMPTY:
return ENOTEMPTY;
default:
/* We just return a generic I/O error if we could not find a relevant error. */
return EIO;
}
}

static void _updateErrno(int success) {
errno = success ? 0 : _wsaErrorToErrno(WSAGetLastError());
}

static int _initWinsock() {
static int s_initialized = 0;
if (!s_initialized) {
static WSADATA wsadata;
int err = WSAStartup(MAKEWORD(2,2), &wsadata);
if (err != 0) {
errno = _wsaErrorToErrno(err);
return 0;
}
s_initialized = 1;
}
return 1;
}

int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
/* Note: This function is likely to be called before other functions, so run init here. */
if (!_initWinsock()) {
return EAI_FAIL;
}

switch (getaddrinfo(node, service, hints, res)) {
case 0: return 0;
case WSATRY_AGAIN: return EAI_AGAIN;
case WSAEINVAL: return EAI_BADFLAGS;
case WSAEAFNOSUPPORT: return EAI_FAMILY;
case WSA_NOT_ENOUGH_MEMORY: return EAI_MEMORY;
case WSAHOST_NOT_FOUND: return EAI_NONAME;
case WSATYPE_NOT_FOUND: return EAI_SERVICE;
case WSAESOCKTNOSUPPORT: return EAI_SOCKTYPE;
default: return EAI_FAIL; /* Including WSANO_RECOVERY */
}
}

const char *win32_gai_strerror(int errcode) {
switch (errcode) {
case 0: errcode = 0; break;
case EAI_AGAIN: errcode = WSATRY_AGAIN; break;
case EAI_BADFLAGS: errcode = WSAEINVAL; break;
case EAI_FAMILY: errcode = WSAEAFNOSUPPORT; break;
case EAI_MEMORY: errcode = WSA_NOT_ENOUGH_MEMORY; break;
case EAI_NONAME: errcode = WSAHOST_NOT_FOUND; break;
case EAI_SERVICE: errcode = WSATYPE_NOT_FOUND; break;
case EAI_SOCKTYPE: errcode = WSAESOCKTNOSUPPORT; break;
default: errcode = WSANO_RECOVERY; break; /* Including EAI_FAIL */
}
return gai_strerror(errcode);
}

void win32_freeaddrinfo(struct addrinfo *res) {
freeaddrinfo(res);
}

SOCKET win32_socket(int domain, int type, int protocol) {
SOCKET s;

/* Note: This function is likely to be called before other functions, so run init here. */
if (!_initWinsock()) {
return INVALID_SOCKET;
}

_updateErrno((s = socket(domain, type, protocol)) != INVALID_SOCKET);
return s;
}

int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp) {
int ret = ioctlsocket(fd, (long)request, argp);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}

int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int ret = bind(sockfd, addr, addrlen);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}

int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen) {
int ret = connect(sockfd, addr, addrlen);
_updateErrno(ret != SOCKET_ERROR);

/* For Winsock connect(), the WSAEWOULDBLOCK error means the same thing as
* EINPROGRESS for POSIX connect(), so we do that translation to keep POSIX
* logic consistent. */
if (errno == EWOULDBLOCK) {
errno = EINPROGRESS;
}

return ret != SOCKET_ERROR ? ret : -1;
}

int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen) {
int ret = 0;
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
if (*optlen >= sizeof (struct timeval)) {
struct timeval *tv = optval;
DWORD timeout = 0;
socklen_t dwlen = 0;
ret = getsockopt(sockfd, level, optname, (char *)&timeout, &dwlen);
tv->tv_sec = timeout / 1000;
tv->tv_usec = (timeout * 1000) % 1000000;
} else {
ret = WSAEFAULT;
}
*optlen = sizeof (struct timeval);
} else {
ret = getsockopt(sockfd, level, optname, (char*)optval, optlen);
}
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}

int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen) {
int ret = 0;
if ((level == SOL_SOCKET) && ((optname == SO_RCVTIMEO) || (optname == SO_SNDTIMEO))) {
struct timeval *tv = optval;
DWORD timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000;
ret = setsockopt(sockfd, level, optname, (const char*)&timeout, sizeof(DWORD));
} else {
ret = setsockopt(sockfd, level, optname, (const char*)optval, optlen);
}
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}

int win32_close(SOCKET fd) {
int ret = closesocket(fd);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}

ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags) {
int ret = recv(sockfd, (char*)buf, (int)len, flags);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}

ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags) {
int ret = send(sockfd, (const char*)buf, (int)len, flags);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}

int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
int ret = WSAPoll(fds, nfds, timeout);
_updateErrno(ret != SOCKET_ERROR);
return ret != SOCKET_ERROR ? ret : -1;
}
#endif /* _WIN32 */

+ 0
- 91
俱乐部/Source/hiredis/sockcompat.h Bestand weergeven

@@ -1,91 +0,0 @@
/*
* Copyright (c) 2019, Marcus Geelnard <m at bitsnbites dot eu>
*
* 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 Redis 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.
*/

#ifndef __SOCKCOMPAT_H
#define __SOCKCOMPAT_H

#ifndef _WIN32
/* For POSIX systems we use the standard BSD socket API. */
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#else
/* For Windows we use winsock. */
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 /* To get WSAPoll etc. */
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stddef.h>

#ifdef _MSC_VER
typedef signed long ssize_t;
#endif

/* Emulate the parts of the BSD socket API that we need (override the winsock signatures). */
int win32_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
const char *win32_gai_strerror(int errcode);
void win32_freeaddrinfo(struct addrinfo *res);
SOCKET win32_socket(int domain, int type, int protocol);
int win32_ioctl(SOCKET fd, unsigned long request, unsigned long *argp);
int win32_bind(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
int win32_connect(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen);
int win32_getsockopt(SOCKET sockfd, int level, int optname, void *optval, socklen_t *optlen);
int win32_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen);
int win32_close(SOCKET fd);
ssize_t win32_recv(SOCKET sockfd, void *buf, size_t len, int flags);
ssize_t win32_send(SOCKET sockfd, const void *buf, size_t len, int flags);
typedef ULONG nfds_t;
int win32_poll(struct pollfd *fds, nfds_t nfds, int timeout);

#ifndef REDIS_SOCKCOMPAT_IMPLEMENTATION
#define getaddrinfo(node, service, hints, res) win32_getaddrinfo(node, service, hints, res)
#undef gai_strerror
#define gai_strerror(errcode) win32_gai_strerror(errcode)
#define freeaddrinfo(res) win32_freeaddrinfo(res)
#define socket(domain, type, protocol) win32_socket(domain, type, protocol)
#define ioctl(fd, request, argp) win32_ioctl(fd, request, argp)
#define bind(sockfd, addr, addrlen) win32_bind(sockfd, addr, addrlen)
#define connect(sockfd, addr, addrlen) win32_connect(sockfd, addr, addrlen)
#define getsockopt(sockfd, level, optname, optval, optlen) win32_getsockopt(sockfd, level, optname, optval, optlen)
#define setsockopt(sockfd, level, optname, optval, optlen) win32_setsockopt(sockfd, level, optname, optval, optlen)
#define close(fd) win32_close(fd)
#define recv(sockfd, buf, len, flags) win32_recv(sockfd, buf, len, flags)
#define send(sockfd, buf, len, flags) win32_send(sockfd, buf, len, flags)
#define poll(fds, nfds, timeout) win32_poll(fds, nfds, timeout)
#endif /* REDIS_SOCKCOMPAT_IMPLEMENTATION */
#endif /* _WIN32 */

#endif /* __SOCKCOMPAT_H */

+ 0
- 448
俱乐部/Source/hiredis/ssl.c Bestand weergeven

@@ -1,448 +0,0 @@
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
* Copyright (c) 2019, Redis Labs
*
* 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 Redis 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.
*/

#include "hiredis.h"
#include "async.h"

#include <assert.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include "async_private.h"

void __redisSetError(redisContext *c, int type, const char *str);

/* The SSL context is attached to SSL/TLS connections as a privdata. */
typedef struct redisSSLContext {
/**
* OpenSSL SSL_CTX; It is optional and will not be set when using
* user-supplied SSL.
*/
SSL_CTX *ssl_ctx;

/**
* OpenSSL SSL object.
*/
SSL *ssl;

/**
* SSL_write() requires to be called again with the same arguments it was
* previously called with in the event of an SSL_read/SSL_write situation
*/
size_t lastLen;

/** Whether the SSL layer requires read (possibly before a write) */
int wantRead;

/**
* Whether a write was requested prior to a read. If set, the write()
* should resume whenever a read takes place, if possible
*/
int pendingWrite;
} redisSSLContext;

/* Forward declaration */
redisContextFuncs redisContextSSLFuncs;

#ifdef HIREDIS_SSL_TRACE
/**
* Callback used for debugging
*/
static void sslLogCallback(const SSL *ssl, int where, int ret) {
const char *retstr;
int should_log = 0;
/* Ignore low-level SSL stuff */

if (where & SSL_CB_ALERT) {
should_log = 1;
}
if (where == SSL_CB_HANDSHAKE_START || where == SSL_CB_HANDSHAKE_DONE) {
should_log = 1;
}
if ((where & SSL_CB_EXIT) && ret == 0) {
should_log = 1;
}

if (!should_log) {
return;
}

retstr = SSL_alert_type_string(ret);
printf("ST(0x%x). %s. R(0x%x)%s\n", where, SSL_state_string_long(ssl), ret, retstr);

if (where == SSL_CB_HANDSHAKE_DONE) {
printf("Using SSL version %s. Cipher=%s\n", SSL_get_version(ssl), SSL_get_cipher_name(ssl));
}
}
#endif

/**
* OpenSSL global initialization and locking handling callbacks.
* Note that this is only required for OpenSSL < 1.1.0.
*/

#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define HIREDIS_USE_CRYPTO_LOCKS
#endif

#ifdef HIREDIS_USE_CRYPTO_LOCKS
typedef pthread_mutex_t sslLockType;
static void sslLockInit(sslLockType *l) {
pthread_mutex_init(l, NULL);
}
static void sslLockAcquire(sslLockType *l) {
pthread_mutex_lock(l);
}
static void sslLockRelease(sslLockType *l) {
pthread_mutex_unlock(l);
}
static pthread_mutex_t *ossl_locks;

static void opensslDoLock(int mode, int lkid, const char *f, int line) {
sslLockType *l = ossl_locks + lkid;

if (mode & CRYPTO_LOCK) {
sslLockAcquire(l);
} else {
sslLockRelease(l);
}

(void)f;
(void)line;
}

static void initOpensslLocks(void) {
unsigned ii, nlocks;
if (CRYPTO_get_locking_callback() != NULL) {
/* Someone already set the callback before us. Don't destroy it! */
return;
}
nlocks = CRYPTO_num_locks();
ossl_locks = hi_malloc(sizeof(*ossl_locks) * nlocks);
for (ii = 0; ii < nlocks; ii++) {
sslLockInit(ossl_locks + ii);
}
CRYPTO_set_locking_callback(opensslDoLock);
}
#endif /* HIREDIS_USE_CRYPTO_LOCKS */

/**
* SSL Connection initialization.
*/

static int redisSSLConnect(redisContext *c, SSL_CTX *ssl_ctx, SSL *ssl) {
if (c->privdata) {
__redisSetError(c, REDIS_ERR_OTHER, "redisContext was already associated");
return REDIS_ERR;
}
c->privdata = calloc(1, sizeof(redisSSLContext));

c->funcs = &redisContextSSLFuncs;
redisSSLContext *rssl = c->privdata;

rssl->ssl_ctx = ssl_ctx;
rssl->ssl = ssl;

SSL_set_mode(rssl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_set_fd(rssl->ssl, c->fd);
SSL_set_connect_state(rssl->ssl);

ERR_clear_error();
int rv = SSL_connect(rssl->ssl);
if (rv == 1) {
return REDIS_OK;
}

rv = SSL_get_error(rssl->ssl, rv);
if (((c->flags & REDIS_BLOCK) == 0) &&
(rv == SSL_ERROR_WANT_READ || rv == SSL_ERROR_WANT_WRITE)) {
return REDIS_OK;
}

if (c->err == 0) {
char err[512];
if (rv == SSL_ERROR_SYSCALL)
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",strerror(errno));
else {
unsigned long e = ERR_peek_last_error();
snprintf(err,sizeof(err)-1,"SSL_connect failed: %s",
ERR_reason_error_string(e));
}
__redisSetError(c, REDIS_ERR_IO, err);
}
return REDIS_ERR;
}

int redisInitiateSSL(redisContext *c, SSL *ssl) {
return redisSSLConnect(c, NULL, ssl);
}

int redisSecureConnection(redisContext *c, const char *capath,
const char *certpath, const char *keypath, const char *servername) {

SSL_CTX *ssl_ctx = NULL;
SSL *ssl = NULL;

/* Initialize global OpenSSL stuff */
static int isInit = 0;
if (!isInit) {
isInit = 1;
SSL_library_init();
#ifdef HIREDIS_USE_CRYPTO_LOCKS
initOpensslLocks();
#endif
}

ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (!ssl_ctx) {
__redisSetError(c, REDIS_ERR_OTHER, "Failed to create SSL_CTX");
goto error;
}

#ifdef HIREDIS_SSL_TRACE
SSL_CTX_set_info_callback(ssl_ctx, sslLogCallback);
#endif
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
if ((certpath != NULL && keypath == NULL) || (keypath != NULL && certpath == NULL)) {
__redisSetError(c, REDIS_ERR_OTHER, "certpath and keypath must be specified together");
goto error;
}

if (capath) {
if (!SSL_CTX_load_verify_locations(ssl_ctx, capath, NULL)) {
__redisSetError(c, REDIS_ERR_OTHER, "Invalid CA certificate");
goto error;
}
}
if (certpath) {
if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, certpath)) {
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client certificate");
goto error;
}
if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, keypath, SSL_FILETYPE_PEM)) {
__redisSetError(c, REDIS_ERR_OTHER, "Invalid client key");
goto error;
}
}

ssl = SSL_new(ssl_ctx);
if (!ssl) {
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't create new SSL instance");
goto error;
}
if (servername) {
if (!SSL_set_tlsext_host_name(ssl, servername)) {
__redisSetError(c, REDIS_ERR_OTHER, "Couldn't set server name indication");
goto error;
}
}

return redisSSLConnect(c, ssl_ctx, ssl);

error:
if (ssl) SSL_free(ssl);
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
return REDIS_ERR;
}

static int maybeCheckWant(redisSSLContext *rssl, int rv) {
/**
* If the error is WANT_READ or WANT_WRITE, the appropriate flags are set
* and true is returned. False is returned otherwise
*/
if (rv == SSL_ERROR_WANT_READ) {
rssl->wantRead = 1;
return 1;
} else if (rv == SSL_ERROR_WANT_WRITE) {
rssl->pendingWrite = 1;
return 1;
} else {
return 0;
}
}

/**
* Implementation of redisContextFuncs for SSL connections.
*/

static void redisSSLFreeContext(void *privdata){
redisSSLContext *rsc = privdata;

if (!rsc) return;
if (rsc->ssl) {
SSL_free(rsc->ssl);
rsc->ssl = NULL;
}
if (rsc->ssl_ctx) {
SSL_CTX_free(rsc->ssl_ctx);
rsc->ssl_ctx = NULL;
}
free(rsc);
}

static int redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
redisSSLContext *rssl = c->privdata;

int nread = SSL_read(rssl->ssl, buf, bufcap);
if (nread > 0) {
return nread;
} else if (nread == 0) {
__redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");
return -1;
} else {
int err = SSL_get_error(rssl->ssl, nread);
if (c->flags & REDIS_BLOCK) {
/**
* In blocking mode, we should never end up in a situation where
* we get an error without it being an actual error, except
* in the case of EINTR, which can be spuriously received from
* debuggers or whatever.
*/
if (errno == EINTR) {
return 0;
} else {
const char *msg = NULL;
if (errno == EAGAIN) {
msg = "Resource temporarily unavailable";
}
__redisSetError(c, REDIS_ERR_IO, msg);
return -1;
}
}

/**
* We can very well get an EWOULDBLOCK/EAGAIN, however
*/
if (maybeCheckWant(rssl, err)) {
return 0;
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
}
}

static int redisSSLWrite(redisContext *c) {
redisSSLContext *rssl = c->privdata;

size_t len = rssl->lastLen ? rssl->lastLen : sdslen(c->obuf);
int rv = SSL_write(rssl->ssl, c->obuf, len);

if (rv > 0) {
rssl->lastLen = 0;
} else if (rv < 0) {
rssl->lastLen = len;

int err = SSL_get_error(rssl->ssl, rv);
if ((c->flags & REDIS_BLOCK) == 0 && maybeCheckWant(rssl, err)) {
return 0;
} else {
__redisSetError(c, REDIS_ERR_IO, NULL);
return -1;
}
}
return rv;
}

static void redisSSLAsyncRead(redisAsyncContext *ac) {
int rv;
redisSSLContext *rssl = ac->c.privdata;
redisContext *c = &ac->c;

rssl->wantRead = 0;

if (rssl->pendingWrite) {
int done;

/* This is probably just a write event */
rssl->pendingWrite = 0;
rv = redisBufferWrite(c, &done);
if (rv == REDIS_ERR) {
__redisAsyncDisconnect(ac);
return;
} else if (!done) {
_EL_ADD_WRITE(ac);
}
}

rv = redisBufferRead(c);
if (rv == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
_EL_ADD_READ(ac);
redisProcessCallbacks(ac);
}
}

static void redisSSLAsyncWrite(redisAsyncContext *ac) {
int rv, done = 0;
redisSSLContext *rssl = ac->c.privdata;
redisContext *c = &ac->c;

rssl->pendingWrite = 0;
rv = redisBufferWrite(c, &done);
if (rv == REDIS_ERR) {
__redisAsyncDisconnect(ac);
return;
}

if (!done) {
if (rssl->wantRead) {
/* Need to read-before-write */
rssl->pendingWrite = 1;
_EL_DEL_WRITE(ac);
} else {
/* No extra reads needed, just need to write more */
_EL_ADD_WRITE(ac);
}
} else {
/* Already done! */
_EL_DEL_WRITE(ac);
}

/* Always reschedule a read */
_EL_ADD_READ(ac);
}

redisContextFuncs redisContextSSLFuncs = {
.free_privdata = redisSSLFreeContext,
.async_read = redisSSLAsyncRead,
.async_write = redisSSLAsyncWrite,
.read = redisSSLRead,
.write = redisSSLWrite
};


+ 0
- 1017
俱乐部/Source/hiredis/test.c
Diff onderdrukt omdat het te groot bestand
Bestand weergeven


+ 0
- 70
俱乐部/Source/hiredis/test.sh Bestand weergeven

@@ -1,70 +0,0 @@
#!/bin/sh -ue

REDIS_SERVER=${REDIS_SERVER:-redis-server}
REDIS_PORT=${REDIS_PORT:-56379}
REDIS_SSL_PORT=${REDIS_SSL_PORT:-56443}
TEST_SSL=${TEST_SSL:-0}
SSL_TEST_ARGS=

tmpdir=$(mktemp -d)
PID_FILE=${tmpdir}/hiredis-test-redis.pid
SOCK_FILE=${tmpdir}/hiredis-test-redis.sock

if [ "$TEST_SSL" = "1" ]; then
SSL_CA_CERT=${tmpdir}/ca.crt
SSL_CA_KEY=${tmpdir}/ca.key
SSL_CERT=${tmpdir}/redis.crt
SSL_KEY=${tmpdir}/redis.key

openssl genrsa -out ${tmpdir}/ca.key 4096
openssl req \
-x509 -new -nodes -sha256 \
-key ${SSL_CA_KEY} \
-days 3650 \
-subj '/CN=Hiredis Test CA' \
-out ${SSL_CA_CERT}
openssl genrsa -out ${SSL_KEY} 2048
openssl req \
-new -sha256 \
-key ${SSL_KEY} \
-subj '/CN=Hiredis Test Cert' | \
openssl x509 \
-req -sha256 \
-CA ${SSL_CA_CERT} \
-CAkey ${SSL_CA_KEY} \
-CAserial ${tmpdir}/ca.txt \
-CAcreateserial \
-days 365 \
-out ${SSL_CERT}

SSL_TEST_ARGS="--ssl-host 127.0.0.1 --ssl-port ${REDIS_SSL_PORT} --ssl-ca-cert ${SSL_CA_CERT} --ssl-cert ${SSL_CERT} --ssl-key ${SSL_KEY}"
fi

cleanup() {
set +e
kill $(cat ${PID_FILE})
rm -rf ${tmpdir}
}
trap cleanup INT TERM EXIT

cat > ${tmpdir}/redis.conf <<EOF
daemonize yes
pidfile ${PID_FILE}
port ${REDIS_PORT}
bind 127.0.0.1
unixsocket ${SOCK_FILE}
EOF

if [ "$TEST_SSL" = "1" ]; then
cat >> ${tmpdir}/redis.conf <<EOF
tls-port ${REDIS_SSL_PORT}
tls-ca-cert-file ${SSL_CA_CERT}
tls-cert-file ${SSL_CERT}
tls-key-file ${SSL_KEY}
EOF
fi

cat ${tmpdir}/redis.conf
${REDIS_SERVER} ${tmpdir}/redis.conf

${TEST_PREFIX:-} ./hiredis-test -h 127.0.0.1 -p ${REDIS_PORT} -s ${SOCK_FILE} ${SSL_TEST_ARGS}

+ 0
- 56
俱乐部/Source/hiredis/win32.h Bestand weergeven

@@ -1,56 +0,0 @@
#ifndef _WIN32_HELPER_INCLUDE
#define _WIN32_HELPER_INCLUDE
#ifdef _MSC_VER

#include <winsock2.h> /* for struct timeval */

#ifndef inline
#define inline __inline
#endif

#ifndef strcasecmp
#define strcasecmp stricmp
#endif

#ifndef strncasecmp
#define strncasecmp strnicmp
#endif

#ifndef va_copy
#define va_copy(d,s) ((d) = (s))
#endif

#ifndef snprintf
#define snprintf c99_snprintf

__inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
{
int count = -1;

if (size != 0)
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
if (count == -1)
count = _vscprintf(format, ap);

return count;
}

__inline int c99_snprintf(char* str, size_t size, const char* format, ...)
{
int count;
va_list ap;

va_start(ap, format);
count = c99_vsnprintf(str, size, format, ap);
va_end(ap);

return count;
}
#endif
#endif /* _MSC_VER */

#ifdef _WIN32
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)
#endif /* _WIN32 */

#endif /* _WIN32_HELPER_INCLUDE */

Laden…
Annuleren
Opslaan