Hi, This patch is based on the original code by Titus Jose on GitHub, I updated it to work with the development branch and have added some documentation.
Duncan Bellamy
--- a/conf/dynamicmaps.cf 2014-05-30 12:38:33.000000000 +0100 +++ b/conf/dynamicmaps.cf 2020-09-23 20:42:28.001667576 +0100 @@ -5,5 +5,6 @@ lmdb ${LIB_PREFIX}lmdb${LIB_SUFFIX} dict mysql ${LIB_PREFIX}mysql${LIB_SUFFIX} dict_mysql_open pcre ${LIB_PREFIX}pcre${LIB_SUFFIX} dict_pcre_open pgsql ${LIB_PREFIX}pgsql${LIB_SUFFIX} dict_pgsql_open +redis ${LIB_PREFIX}redis${LIB_SUFFIX} dict_redis_open sdbm ${LIB_PREFIX}sdbm${LIB_SUFFIX} dict_sdbm_open mkmap_sdbm_open sqlite ${LIB_PREFIX}sqlite${LIB_SUFFIX} dict_sqlite_open diff -Nurp a/conf/postfix-files b/conf/postfix-files --- a/conf/postfix-files 2019-01-29 22:24:42.000000000 +0000 +++ b/conf/postfix-files 2020-09-23 20:48:19.527925031 +0100 @@ -78,6 +78,7 @@ $shlib_directory/${LIB_PREFIX}lmdb${LIB_ $shlib_directory/${LIB_PREFIX}mysql${LIB_SUFFIX}:f:root:-:755 $shlib_directory/${LIB_PREFIX}pcre${LIB_SUFFIX}:f:root:-:755 $shlib_directory/${LIB_PREFIX}pgsql${LIB_SUFFIX}:f:root:-:755 +$shlib_directory/${LIB_PREFIX}redis${LIB_SUFFIX}:f:root:-:755 $shlib_directory/${LIB_PREFIX}sdbm${LIB_SUFFIX}:f:root:-:755 $shlib_directory/${LIB_PREFIX}sqlite${LIB_SUFFIX}:f:root:-:755 $meta_directory/dynamicmaps.cf.d:d:root:-:755 @@ -200,6 +201,7 @@ $manpage_directory/man5/sqlite_table.5:f $manpage_directory/man5/nisplus_table.5:f:root:-:644 $manpage_directory/man5/pcre_table.5:f:root:-:644 $manpage_directory/man5/pgsql_table.5:f:root:-:644 +$manpage_directory/man5/redis_table.5:f:root:-:644 $manpage_directory/man5/postconf.5:f:root:-:644 $manpage_directory/man5/postfix-wrapper.5:f:root:-:644 $manpage_directory/man5/regexp_table.5:f:root:-:644 @@ -307,6 +309,7 @@ $readme_directory/OVERVIEW:f:root:-:644 $readme_directory/PACKAGE_README:f:root:-:644 $readme_directory/PCRE_README:f:root:-:644 $readme_directory/PGSQL_README:f:root:-:644 +$readme_directory/REDIS_README:f:root:-:644 $readme_directory/POSTSCREEN_README:f:root:-:644 $readme_directory/QMQP_README:f:root:-:644:o $readme_directory/QSHAPE_README:f:root:-:644 @@ -363,6 +366,7 @@ $html_directory/OVERVIEW.html:f:root:-:6 $html_directory/PACKAGE_README.html:f:root:-:644 $html_directory/PCRE_README.html:f:root:-:644 $html_directory/PGSQL_README.html:f:root:-:644 +$html_directory/REDIS_README.html:f:root:-:644 $html_directory/POSTSCREEN_README.html:f:root:-:644 $html_directory/QMQP_README.html:f:root:-:644:o $html_directory/QSHAPE_README.html:f:root:-:644 @@ -414,6 +418,7 @@ $html_directory/newaliases.1.html:h:$htm $html_directory/oqmgr.8.html:f:root:-:644 $html_directory/pcre_table.5.html:f:root:-:644 $html_directory/pgsql_table.5.html:f:root:-:644 +$html_directory/redis_table.5.html:f:root:-:644 $html_directory/pickup.8.html:f:root:-:644 $html_directory/pipe.8.html:f:root:-:644 $html_directory/postalias.1.html:f:root:-:644 diff -Nurp a/html/REDIS_README.html b/html/REDIS_README.html --- a/makedefs 2020-09-20 22:25:37.000000000 +0100 +++ b/makedefs 2020-09-23 20:42:28.009667536 +0100 @@ -1178,7 +1178,7 @@ DEFINED_MAP_TYPES=` # Propagate AUXLIBS_FOO or merge them into global AUXLIBS (i.e. SYSLIBS). -PLUGGABLE_MAPS="CDB LDAP LMDB MYSQL PCRE PGSQL SDBM SQLITE" +PLUGGABLE_MAPS="CDB LDAP LMDB MYSQL PCRE PGSQL REDIS SDBM SQLITE" case "$dynamicmaps" in yes) for name in $PLUGGABLE_MAPS diff -Nurp a/man/Makefile.in b/man/Makefile.in --- a/man/Makefile.in 2019-01-19 22:12:31.000000000 +0000 +++ b/man/Makefile.in 2020-09-23 21:01:00.416537285 +0100 @@ -17,7 +17,7 @@ CONFIG = man5/access.5 man5/aliases.5 ma man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5 \ man5/cidr_table.5 man5/tcp_table.5 man5/header_checks.5 \ man5/body_checks.5 man5/ldap_table.5 man5/lmdb_table.5 \ - man5/memcache_table.5 man5/mysql_table.5 \ + man5/memcache_table.5 man5/mysql_table.5 man5/redis_table.5 \ man5/pgsql_table.5 man5/master.5 man5/nisplus_table.5 \ man5/generic.5 man5/bounce.5 man5/postfix-wrapper.5 \ man5/sqlite_table.5 man5/socketmap_table.5 @@ -345,6 +345,11 @@ man5/pgsql_table.5: ../proto/pgsql_table ../mantools/fixman ../proto/postconf.proto $? >junk && \ (cmp -s junk $? || mv junk $?) && rm -f junk ../mantools/srctoman - $? >$@ + +man5/redis_table.5: ../proto/redis_table + ../mantools/fixman ../proto/postconf.proto $? >junk && \ + (cmp -s junk $? || mv junk $?) && rm -f junk + ../mantools/srctoman - $? >$@ man5/regexp_table.5: ../proto/regexp_table ../mantools/fixman ../proto/postconf.proto $? >junk && \ diff -Nurp a/src/global/mail_dict.c b/src/global/mail_dict.c --- a/src/global/mail_dict.c 2014-06-22 01:42:55.000000000 +0100 +++ b/src/global/mail_dict.c 2020-09-23 20:42:28.009667536 +0100 @@ -45,6 +45,7 @@ #include <dict_ldap.h> #include <dict_mysql.h> #include <dict_pgsql.h> +#include <dict_redis.h> #include <dict_sqlite.h> #include <dict_memcache.h> #include <mail_dict.h> @@ -68,6 +69,9 @@ static const DICT_OPEN_INFO dict_open_in #ifdef HAS_PGSQL DICT_TYPE_PGSQL, dict_pgsql_open, #endif +#ifdef HAS_REDIS + DICT_TYPE_REDIS, dict_redis_open, +#endif #ifdef HAS_SQLITE DICT_TYPE_SQLITE, dict_sqlite_open, #endif diff -Nurp a/src/global/Makefile.in b/src/global/Makefile.in --- a/src/global/Makefile.in 2020-09-15 00:21:37.000000000 +0100 +++ b/src/global/Makefile.in 2020-09-23 20:42:28.013667515 +0100 @@ -3,7 +3,7 @@ SRCS = abounce.c anvil_clnt.c been_here. canon_addr.c cfg_parser.c cleanup_strerror.c cleanup_strflags.c \ clnt_stream.c conv_time.c db_common.c debug_peer.c debug_process.c \ defer.c deliver_completed.c deliver_flock.c deliver_pass.c \ - deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c \ + deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c dict_redis.c \ dict_proxy.c dict_sqlite.c domain_list.c dot_lockfile.c dot_lockfile_as.c \ dsb_scan.c dsn.c dsn_buf.c dsn_mask.c dsn_print.c dsn_util.c \ ehlo_mask.c ext_prop.c file_id.c flush_clnt.c header_opts.c \ @@ -78,13 +78,13 @@ OBJS = abounce.o anvil_clnt.o been_here. # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf. # When hard-linking these maps, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ), # otherwise it sets the PLUGIN_* macros. -MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_sqlite.o mkmap_cdb.o \ +MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_redis.o dict_sqlite.o mkmap_cdb.o \ mkmap_lmdb.o mkmap_sdbm.o HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ deliver_completed.h deliver_flock.h deliver_pass.h deliver_request.h \ - dict_ldap.h dict_mysql.h dict_pgsql.h dict_proxy.h dict_sqlite.h domain_list.h \ + dict_ldap.h dict_mysql.h dict_pgsql.h dict_redis.h dict_proxy.h dict_sqlite.h domain_list.h \ dot_lockfile.h dot_lockfile_as.h dsb_scan.h dsn.h dsn_buf.h \ dsn_mask.h dsn_print.h dsn_util.h ehlo_mask.h ext_prop.h \ file_id.h flush_clnt.h header_opts.h header_token.h input_transp.h \ @@ -131,7 +131,7 @@ LIBS = ../../lib/lib$(LIB_PREFIX)util$(L LIB_DIR = ../../lib INC_DIR = ../../include PLUGIN_MAP_SO = $(LIB_PREFIX)ldap$(LIB_SUFFIX) $(LIB_PREFIX)mysql$(LIB_SUFFIX) \ - $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX) \ + $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)redis$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX) \ $(LIB_PREFIX)lmdb$(LIB_SUFFIX) $(LIB_PREFIX)cdb$(LIB_SUFFIX) \ $(LIB_PREFIX)sdbm$(LIB_SUFFIX) MAKES = @@ -167,6 +167,9 @@ $(LIB_PREFIX)mysql$(LIB_SUFFIX): dict_my $(LIB_PREFIX)pgsql$(LIB_SUFFIX): dict_pgsql.o $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_pgsql.o $(AUXLIBS_PGSQL) +$(LIB_PREFIX)redis$(LIB_SUFFIX): dict_redis.o + $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_redis.o $(AUXLIBS_REDIS) + $(LIB_PREFIX)sqlite$(LIB_SUFFIX): dict_sqlite.o $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_sqlite.o $(AUXLIBS_SQLITE) @@ -521,6 +524,8 @@ surrogate_test: mail_dict surrogate.ref echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict mysql:/xx read >>surrogate.tmp 2>&1 echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict pgsql:/xx write >>surrogate.tmp 2>&1 echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict pgsql:/xx read >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict redis:/xx write >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict redis:/xx read >>surrogate.tmp 2>&1 echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict sqlite:/xx write >>surrogate.tmp 2>&1 echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict sqlite:/xx read >>surrogate.tmp 2>&1 echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict memcache:/xx read >>surrogate.tmp 2>&1 @@ -1184,6 +1189,17 @@ dict_pgsql.o: db_common.h dict_pgsql.o: dict_pgsql.c dict_pgsql.o: dict_pgsql.h dict_pgsql.o: string_list.h +dict_redis.o: ../../include/dict.h +dict_redis.o: ../../include/msg.h +dict_redis.o: ../../include/mymalloc.h +dict_redis.o: ../../include/vbuf.h +dict_redis.o: ../../include/vstream.h +dict_redis.o: ../../include/vstring.h +dict_redis.o: ../../include/stringops.h +dict_redis.o: ../../include/sys_defs.h +dict_redis.o: cfg_parser.h +dict_redis.o: dict_redis.c +dict_redis.o: dict_redis.h dict_proxy.o: ../../include/argv.h dict_proxy.o: ../../include/attr.h dict_proxy.o: ../../include/check_arg.h @@ -1770,6 +1786,7 @@ mail_dict.o: dict_ldap.h mail_dict.o: dict_memcache.h mail_dict.o: dict_mysql.h mail_dict.o: dict_pgsql.h +mail_dict.o: dict_redis.h mail_dict.o: dict_proxy.h mail_dict.o: dict_sqlite.h mail_dict.o: dynamicmaps.h diff -Nurp a/html/REDIS_README.html b/html/REDIS_README.html --- a/html/REDIS_README.html 1970-01-01 01:00:00.000000000 +0100 +++ b/html/REDIS_README.html 2021-02-27 08:47:15.302235467 +0000 @@ -0,0 +1,105 @@ +<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> + +<html> + +<head> + +<title>Postfix Redis Howto</title> + +<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> + +</head> + +<body> + +<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix Redis Howto</h1> + +<hr> + +<h2>Introduction</h2> + +<p> The Postfix redis map type allows you to hook up Postfix to a +Redis database. </p> + +<h2>Building Postfix with Redis support</h2> + +<p> These instructions assume that you build Postfix from source +code as described in the <a href="INSTALL.html">INSTALL</a> document. Some modification may +be required if you build Postfix from a vendor-specific source +package. </p> + +<p> In order to build Postfix with redis map support, you specify +-DHAS_REDIS, the directory with the hiredis header files, and +the location of the hiredis library file. </p> + +<p> For example: </p> + +<blockquote> +<pre> +% make tidy +% make -f Makefile.init makefiles \ + 'CCARGS=-DHAS_REDIS $(pkg-config --cflags hiredis)' \ + '<a href="REDIS_README.html">AUXLIBS_REDIS</a>=$(pkg-config --libs hiredis)' +</pre> +</blockquote> + +<blockquote> + +<p> Failure to use the <a href="REDIS_README.html">AUXLIBS_REDIS</a> variable will defeat the purpose +of dynamic database client loading. Every Postfix executable file +will have Redis database library dependencies. And that was exactly +what dynamic database client loading was meant to avoid. </p> + +</blockquote> + +<p> Then just run 'make'. </p> + +<h2>Configuring Redis lookup tables</h2> + +<p> Once Postfix is built with redis support, you can specify a +map type in <a href="postconf.5.html">main.cf</a> like this: </p> + +<blockquote> +<pre> +/etc/postfix/<a href="postconf.5.html">main.cf</a>: + <a href="postconf.5.html#alias_maps">alias_maps</a> = <a href="redis_table.5.html">redis</a>:/etc/postfix/redis-aliases.cf +</pre> +</blockquote> + +<p> The file /etc/postfix/redis-aliases.cf specifies how to reach the redis database. +For a complete description, see the <a href="redis_table.5.html">redis_table(5)</a> manual page. </p> + +<h2>Example: local aliases </h2> + +<pre> +# +# redis config file for <a href="virtual.8.html">virtual(8)</a> lookups +# + +# +# The hosts that Postfix will try to connect to +host = 127.0.0.1 + +# The prefix added to the query to check with redis +prefix = VDOM: +</pre> + +<h2>Using mirrored databases</h2> + +<p> Sites that have a need for multiple mail exchangers can setup a redis cluster +if needed, for fallover capability. </p> + +<h2>Credits</h2> + +<ul> + +<li> This code is originaly by Titus T Jose.</li> + +<li> It has been updated by Duncan Bellamy.</li> + +</ul> + +</body> + +</html> diff -Nurp a/man/man5/redis_table.5 b/man/man5/redis_table.5 --- a/man/man5/redis_table.5 1970-01-01 01:00:00.000000000 +0100 +++ b/man/man5/redis_table.5 2021-02-27 08:47:15.290235523 +0000 @@ -0,0 +1,108 @@ +.TH REDIS_TABLE 5 +.ad +.fi +.SH NAME +redis_table +\- +Postfix Redis client configuration +.SH "SYNOPSIS" +.na +.nf +\fBpostmap \-q "\fIprefix:string\fB" redis:/etc/postfix/\fIfilename\fR + +\fBpostmap \-q \- redis:/etc/postfix/\fIfilename\fB <\fIinputfile\fR +.SH DESCRIPTION +.ad +.fi +The Postfix mail system uses optional tables for address +rewriting or mail routing. These tables are usually in +\fBdbm\fR or \fBdb\fR format. + +Alternatively, lookup tables can be specified as Redis +databases. In order to use Redis lookups, define a +Redis source as a lookup table in main.cf, for example: +.nf + virtual_alias_maps = redis:/etc/postfix/redis\-valias\-maps.cf +.fi + +The file /etc/postfix/redis\-valias\-maps.cf has the same format as +the Postfix main.cf file, and can specify the parameters +described below. +.SH "host" +.na +.nf +.ad +.fi +The IP address of the host that Postfix will try to connect to and query +from. + +Example: +.nf + host = 127.0.0.1 +.fi + +.SH "port" +.na +.nf +.ad +.fi +.IP "\fBport\fR" +The port that Postfix will use trying to connect to and query +from the Redis server. If not specified the default of \fB6379://\fR +will be used. + +Example: +.nf + port = 6379 +.fi + +.IP "\fBprefix\fR" +This is the prefix that is added to the query from postfix before it is passed to +redis for a lookup, allowing postfix to use simple key:value lookups from Redis. + +Examples: +.nf + prefix = VALI + prefix = LOCAL + prefix = REV + prefix = HELO +.fi + +.SH "SEE ALSO" +.na +.nf +postmap(1), Postfix lookup table manager +postconf(5), configuration parameters +ldap_table(5), LDAP lookup tables +mysql_table(5), MySQL lookup tables +sqlite_table(5), SQLite lookup tables +.SH "README FILES" +.na +.nf +.ad +.fi +Use "\fBpostconf readme_directory\fR" or +"\fBpostconf html_directory\fR" to locate this information. +.na +.nf +DATABASE_README, Postfix lookup table overview +REDIS_README +.SH "LICENSE" +.na +.nf +.ad +.fi +The Secure Mailer license must be distributed with this software. +.SH HISTORY +.ad +.fi +Redis support was introduced with Postfix version 3.? +.SH "AUTHOR(S)" +.na +.nf +Titus Jose +titus.n...@gmail.com + +Updated by: +Duncan Bellamy +d...@denkimushi.com \ No newline at end of file diff -Nurp a/README_FILES/REDIS_README b/README_FILES/REDIS_README --- a/README_FILES/REDIS_README 1970-01-01 01:00:00.000000000 +0100 +++ b/README_FILES/REDIS_README 2021-02-27 08:47:15.294235504 +0000 @@ -0,0 +1,64 @@ +@@ -0,0 1,123 @@ +PPoossttffiixx PPoossttggrreeSSQQLL HHoowwttoo + +------------------------------------------------------------------------------- + +IInnttrroodduuccttiioonn + +The Postfix redis map type allows you to hook up Postfix to a Redis +database. + +BBuuiillddiinngg PPoossttffiixx wwiitthh PPoossttggrreeSSQQLL ssuuppppoorrtt + +These instructions assume that you build Postfix from source code as described +in the INSTALL document. Some modification may be required if you build Postfix +from a vendor-specific source package. + +In order to build Postfix with redis map support, you specify -DHAS_REDIS, the +directory with the hiredis header files, and the location of the hiredis +library file. + +For example: + + % make tidy + % make -f Makefile.init makefiles \ + 'CCARGS=-DHAS_REDIS $(pkg-config --cflags hiredis)' \ + 'AUXLIBS_REDIS=$(pkg-config --libs hiredis)' + +Then just run 'make'. + +CCoonnffiigguurriinngg PPoossttggrreeSSQQLL llooookkuupp ttaabblleess + +Once Postfix is built with redis support, you can specify a map type in main.cf +like this: + + /etc/postfix/main.cf: + virtual_mailbox_domains = redis:${config_directory}/redis-vdomains.cf + +The file ${config_directory}/redis-vdomains.cf specifies the information telling +postfix how to connect to the redis database. It also has the prefix used to find +the required key. For a complete description, see +the redis_table(5) manual page. + +EExxaammppllee:: llooccaall aalliiaasseess + +# +# redis config file for virtual(8) lookups +# + +# +# The hosts that Postfix will try to connect to +host = 127.0.0.1 + +# The prefix added to the query to check with redis +prefix = VDOM: + +UUssiinngg mmiirrrroorreedd ddaattaabbaasseess + +Sites that have a need for multiple mail exchangers can setup a redis cluster +if needed, for fallover capability. + +CCrreeddiittss + + * This code is originaly by Titus T Jose. + * It has been updated by Duncan Bellamy. diff -Nurp a/src/global/dict_redis.c b/src/global/dict_redis.c --- a/src/global/dict_redis.c 1970-01-01 01:00:00.000000000 +0100 +++ b/src/global/dict_redis.c 2021-02-27 08:47:15.282235561 +0000 @@ -0,0 +1,217 @@ +/*++ +/* NAME +/* dict_redis 3 +/* SUMMARY +/* dictionary manager interface to Redis databases +/* SYNOPSIS +/* #include <dict_redis.h> +/* +/* DICT *dict_redis_open(name, open_flags, dict_flags) +/* const char *name; +/* int open_flags; +/* int dict_flags; +/* DESCRIPTION +/* dict_redis_open() creates a dictionary of type 'redis'. This +/* dictionary is an interface for the postfix key->value mappings +/* to redis. The result is a pointer to the installed dictionary, +/* or a null pointer in case of problems. +/* .PP +/* Arguments: +/* .IP name +/* Either the path to the Redis configuration file (if it +/* starts with '/' or '.'), or the prefix which will be used to +/* obtain main.cf configuration parameters for this search. +/* +/* In the first case, the configuration parameters below are +/* specified in the file as \fIname\fR=\fIvalue\fR pairs. +/* +/* In the second case, the configuration parameters are +/* prefixed with the value of \fIname\fR and an underscore, +/* and they are specified in main.cf. For example, if this +/* value is \fIredisDB\fR, the parameters would look like +/* \fIredisDB_host\fR, \fIpredisDB_prefix\fR, and so on. +/* .IP other_name +/* reference for outside use. +/* .IP open_flags +/* unused. +/* .IP dict_flags +/* See dict_open(3). +/* +/* .PP +/* Configuration parameters: +/* .IP host +/* IP address of the redis server hosting the database. +/* .IP port +/* Port number to connect to the above. +/* .IP prefix +/* Prefix to add to the key when looking it up. +/* .PP +/* For example, if you want the map to reference databases on +/* redis host "127.0.0.1" and prefix the query with VDOM: +/* Then the configuration file +/* should read: +/* .PP +/* host = 127.0.0.1 +/* .br +/* port = 6379 +/* .br +/* prefix = VDOM: +/* .PP +/* SEE ALSO +/* dict(3) generic dictionary manager +/* AUTHOR(S) +/* Titus Jose +/* titus.n...@gmail.com +/* +/* Updated by: +/* Duncan Bellamy +/* d...@denkimushi.com +/*--*/ + +#include "sys_defs.h" + +#ifdef HAS_REDIS +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include "msg.h" +#include "dict.h" +#include "mymalloc.h" +#include "vstring.h" +#include "stringops.h" + +/* Global library. */ + +#include "cfg_parser.h" + +/* Application-specific. */ + +#include "dict_redis.h" +#include "hiredis.h" + +typedef struct { + DICT dict; + CFG_PARSER *parser; + redisContext *c; + char *host; + int port; + char *prefix; +} DICT_REDIS; + +/* internal function declarations */ +static const char *dict_redis_lookup(DICT *, const char *); +DICT *dict_redis_open(const char *, int, int); +static void dict_redis_close(DICT *); +static void redis_parse_config(DICT_REDIS *, const char *); + + +static const char *dict_redis_lookup(DICT *dict, const char *name) +{ + const char *myname = "dict_redis_lookup"; + DICT_REDIS *dict_redis = (DICT_REDIS *) dict; + redisReply *reply; + const char *r; + VSTRING *result; + dict->error = 0; + + result = vstring_alloc(10); + VSTRING_RESET(result); + VSTRING_TERMINATE(result); + + + if (msg_verbose) + msg_info("%s: Requesting key %s%s",dict_redis->host,dict_redis->prefix,name); + /* + * Optionally fold the key. + */ + if (dict->flags & DICT_FLAG_FOLD_FIX) { + if (dict->fold_buf == 0) + dict->fold_buf = vstring_alloc(10); + vstring_strcpy(dict->fold_buf, name); + name = lowercase(vstring_str(dict->fold_buf)); + } + + if(dict_redis->c) { + reply = redisCommand(dict_redis->c,"GET %s%s",dict_redis->prefix,name); + } + else { + dict->error = DICT_ERR_CONFIG; + } + if(reply->str) { + vstring_strcpy(result,reply->str); + r = vstring_str(result); + freeReplyObject(reply); + } + else { + return(0); + } + return ((dict->error == 0 && *r) ? r : 0); +} + +/* redis_parse_config - parse redis configuration file */ + +static void redis_parse_config(DICT_REDIS *dict_redis, const char *rediscf) +{ + const char *myname = "redisname_parse"; + CFG_PARSER *p = dict_redis->parser; + + dict_redis->port = cfg_get_int(p, "port", 6379, 0, 0); + dict_redis->host = cfg_get_str(p, "host", "127.0.0.1", 1, 0); + dict_redis->prefix = cfg_get_str(p, "prefix", "", 0, 0); +} + +/* dict_redis_open - open redis data base */ + +DICT *dict_redis_open(const char *name, int open_flags, int dict_flags) +{ + DICT_REDIS *dict_redis; + CFG_PARSER *parser; + redisContext *c; + + /* + * Open the configuration file. + */ + if ((parser = cfg_parser_alloc(name)) == 0) + return (dict_surrogate(DICT_TYPE_REDIS, name, open_flags, dict_flags, + "open %s: %m", name)); + + dict_redis = (DICT_REDIS *) dict_alloc(DICT_TYPE_REDIS, name, + sizeof(DICT_REDIS)); + dict_redis->dict.lookup = dict_redis_lookup; + dict_redis->dict.close = dict_redis_close; + dict_redis->dict.flags = dict_flags; + dict_redis->parser = parser; + redis_parse_config(dict_redis, name); + dict_redis->dict.owner = cfg_get_owner(dict_redis->parser); + c = redisConnect(dict_redis->host,dict_redis->port); + if(c->err) { + msg_fatal("%s:%s: Cannot connect to Redis server %s: %s\n", + DICT_TYPE_REDIS, name, dict_redis->host, c->errstr); + } else { + dict_redis->c = c; + } + + return (DICT_DEBUG (&dict_redis->dict)); +} + +/* dict_redis_close - close redis database */ + +static void dict_redis_close(DICT *dict) +{ + DICT_REDIS *dict_redis = (DICT_REDIS *) dict; + + cfg_parser_free(dict_redis->parser); + myfree(dict_redis->host); + if (dict->fold_buf) + vstring_free(dict->fold_buf); + dict_free(dict); +} + +#endif diff -Nurp a/src/global/dict_redis.h b/src/global/dict_redis.h --- a/src/global/dict_redis.h 1970-01-01 01:00:00.000000000 +0100 +++ b/src/global/dict_redis.h 2021-02-27 08:47:15.282235561 +0000 @@ -0,0 +1,10 @@ +#ifndef _DICT_REDIS_H_INCLUDED_ +#define _DICT_REDIS_H_INCLUDED_ + +#include <dict.h> + +#define DICT_TYPE_REDIS "redis" + +extern DICT *dict_redis_open(const char *, int, int); + +#endif