Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #ifndef __REDIS_CONNECTION__H__ 7 : #define __REDIS_CONNECTION__H__ 8 : 9 : #include <mutex> 10 : #include <string> 11 : 12 : #include <boost/asio.hpp> 13 : #include <boost/scoped_ptr.hpp> 14 : #include <boost/ptr_container/ptr_map.hpp> 15 : #include "hiredis/hiredis.h" 16 : #include "hiredis/async.h" 17 : #include "hiredis/boostasio.hpp" 18 : #include "io/event_manager.h" 19 : 20 : /* 21 : * Class for maintaining an async connection to Redis, aka RAC - redis async connection 22 : */ 23 : class RedisAsyncConnection { 24 : public: 25 : static const int RedisReconnectTime = 5; 26 : 27 : typedef boost::function<void (void)> ClientConnectCbFn; 28 : typedef boost::function<void (void)> ClientDisconnectCbFn; 29 : typedef boost::function<void (const redisAsyncContext *c, void *r, void *privdata)> ClientAsyncCmdCbFn; 30 : typedef boost::function<void (const redisReply *reply)> RAC_StatCbFn; 31 : typedef boost::function<void (const struct redisAsyncContext*, int)> RAC_ConnectCbFn; 32 : typedef boost::function<void (const struct redisAsyncContext*, int)> RAC_DisconnectCbFn; 33 : 34 : struct RAC_CbFns { 35 275 : RAC_CbFns() : 36 275 : stat_cbfn_(NULL), 37 275 : connect_cbfn_(NULL), 38 275 : disconnect_cbfn_(NULL), 39 275 : client_async_cmd_cbfn_(NULL) { } 40 : RAC_StatCbFn stat_cbfn_; 41 : RAC_ConnectCbFn connect_cbfn_; 42 : RAC_DisconnectCbFn disconnect_cbfn_; 43 : ClientAsyncCmdCbFn client_async_cmd_cbfn_; 44 : }; 45 : 46 : typedef boost::ptr_map<const redisAsyncContext *, RAC_CbFns> RAC_CbFnsMap; 47 : 48 : RedisAsyncConnection(EventManager *evm, const std::string & redis_ip, 49 : unsigned short redis_port, ClientConnectCbFn client_connect_cb = NULL, 50 : ClientDisconnectCbFn client_disconnect_cb = NULL, 51 : const bool redis_ssl_enable = false, 52 : const std::string & redis_keyfile = std::string(), 53 : const std::string & redis_certfile = std::string(), 54 : const std::string & redis_ca_cert = std::string()); 55 : virtual ~RedisAsyncConnection(); 56 : 57 : bool RAC_Connect(void); 58 : 59 : bool IsConnUp() { 60 : return (state_ == REDIS_ASYNC_CONNECTION_CONNECTED); 61 : } 62 : bool SetClientAsyncCmdCb(ClientAsyncCmdCbFn cb_fn); 63 : bool RedisAsyncCommand(void *rpi, const char *format, ...); 64 : bool RedisAsyncArgCmd(void *rpi, const std::vector<std::string> &args); 65 : void RAC_StatUpdate(const redisReply *reply); 66 : 67 4652 : static RAC_CbFnsMap& rac_cb_fns_map() { 68 4652 : return rac_cb_fns_map_; 69 : } 70 : EventManager * GetEVM() { return evm_; } 71 : 72 : uint64_t CallDisconnected() { return callDisconnected_; } 73 : uint64_t CallFailed() { return callFailed_; } 74 : uint64_t CallSucceeded() { return callSucceeded_; } 75 : uint64_t CallbackNull() { return callbackNull_; } 76 : uint64_t CallbackFailed() { return callbackFailed_; } 77 : uint64_t CallbackSucceeded() { return callbackSucceeded_; } 78 : 79 760 : boost::asio::ip::tcp::endpoint Endpoint() const { return endpoint_; } 80 : private: 81 : enum RedisState { 82 : REDIS_ASYNC_CONNECTION_INIT = 0, 83 : REDIS_ASYNC_CONNECTION_PENDING = 1, 84 : REDIS_ASYNC_CONNECTION_CONNECTED = 2, 85 : REDIS_ASYNC_CONNECTION_DISCONNECTED = 3, 86 : }; 87 : 88 : EventManager *evm_; 89 : const std::string hostname_; 90 : const unsigned short port_; 91 : const bool redis_ssl_enable_; 92 : const std::string redis_keyfile_; 93 : const std::string redis_certfile_; 94 : const std::string redis_ca_cert_; 95 : 96 : uint64_t callDisconnected_; 97 : uint64_t callFailed_; 98 : uint64_t callSucceeded_; 99 : uint64_t callbackNull_; 100 : uint64_t callbackFailed_; 101 : uint64_t callbackSucceeded_; 102 : 103 : redisAsyncContext *context_; 104 : //boost::scoped_ptr<redisBoostClient> client_; 105 : boost::shared_ptr<redisBoostClient> client_; 106 : std::mutex mutex_; 107 : RedisState state_; 108 : boost::asio::deadline_timer reconnect_timer_; 109 : 110 : void RAC_Reconnect(const boost::system::error_code &error); 111 : 112 : /* the flow for connect callback is 113 : * 1. RAC_ConnectCallback gets called from hiredis lib 114 : * 2. A lookup against redisAsyncContext in rac_cb_fns_map_ yields 115 : * RAC_ConnectCallbackProcess_ptr, which is same as 116 : * RAC_ConnectCallbackProcess 117 : * 3. From RAC_ConnectCallbackProcess client's client_connect_cb_ gets called 118 : * 119 : * Flow for other callbacks is similar... 120 : */ 121 : 122 : /* connect callback related fields */ 123 : void RAC_ConnectCallbackProcess(const struct redisAsyncContext *c, int status); 124 : static void RAC_ConnectCallback(const struct redisAsyncContext *c, int status); 125 : //RAC_ConnectCbFn RAC_ConnectCallbackProcess_ptr; 126 : ClientConnectCbFn client_connect_cb_; 127 : 128 : /* disconnect callback related fields */ 129 : void RAC_DisconnectCallbackProcess(const struct redisAsyncContext *c, int status); 130 : static void RAC_DisconnectCallback(const struct redisAsyncContext *c, int status); 131 : //RAC_DisconnectCbFn RAC_DisconnectCallbackProcess_ptr; 132 : ClientDisconnectCbFn client_disconnect_cb_; 133 : 134 : /* async command callback related fields */ 135 : static void RAC_AsyncCmdCallback(redisAsyncContext *c, void *r, void *privdata); 136 : 137 : static RAC_CbFnsMap rac_cb_fns_map_; 138 : static std::mutex rac_cb_fns_map_mutex_; 139 : 140 : boost::asio::ip::tcp::endpoint endpoint_; 141 : }; 142 : #endif