nutcracker 0.4.0.16 → 0.4.1.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -3
  3. data/ext/nutcracker/ChangeLog +33 -8
  4. data/ext/nutcracker/Makefile.in +34 -21
  5. data/ext/nutcracker/README.md +61 -26
  6. data/ext/nutcracker/aclocal.m4 +34 -31
  7. data/ext/nutcracker/autom4te.cache/output.0 +1875 -1330
  8. data/ext/nutcracker/autom4te.cache/output.1 +1875 -1330
  9. data/ext/nutcracker/autom4te.cache/requests +232 -451
  10. data/ext/nutcracker/autom4te.cache/traces.0 +2256 -2129
  11. data/ext/nutcracker/autom4te.cache/traces.1 +73 -59
  12. data/ext/nutcracker/config.h.in +1 -2
  13. data/ext/nutcracker/config.h.in~ +333 -0
  14. data/ext/nutcracker/config/compile +1 -1
  15. data/ext/nutcracker/config/config.guess +13 -160
  16. data/ext/nutcracker/config/config.sub +25 -11
  17. data/ext/nutcracker/config/depcomp +1 -1
  18. data/ext/nutcracker/config/install-sh +170 -196
  19. data/ext/nutcracker/config/ltmain.sh +3509 -2018
  20. data/ext/nutcracker/config/missing +1 -1
  21. data/ext/nutcracker/configure +1874 -1329
  22. data/ext/nutcracker/configure.ac +3 -2
  23. data/ext/nutcracker/contrib/Makefile.in +18 -5
  24. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
  25. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
  26. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +832 -0
  27. data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
  28. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +1157 -0
  29. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/output.0 +13342 -0
  30. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/output.1 +14611 -0
  31. data/ext/nutcracker/{autom4te.cache → contrib/yaml-0.1.4/autom4te.cache}/output.2 +3465 -8761
  32. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/requests +516 -0
  33. data/ext/nutcracker/{autom4te.cache/traces.2 → contrib/yaml-0.1.4/autom4te.cache/traces.0} +662 -698
  34. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/traces.1 +577 -0
  35. data/ext/nutcracker/contrib/yaml-0.1.4/autom4te.cache/traces.2 +2721 -0
  36. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +79 -0
  37. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in~ +80 -0
  38. data/ext/nutcracker/contrib/yaml-0.1.4/config/compile +347 -0
  39. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1421 -0
  40. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1807 -0
  41. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +791 -0
  42. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +501 -0
  43. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +11147 -0
  44. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +215 -0
  45. data/ext/nutcracker/contrib/yaml-0.1.4/config/test-driver +148 -0
  46. data/ext/nutcracker/contrib/yaml-0.1.4/configure +14611 -0
  47. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
  48. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
  49. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
  50. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +8369 -0
  51. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +437 -0
  52. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +124 -0
  53. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
  54. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +99 -0
  55. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
  56. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +600 -0
  57. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
  58. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
  59. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
  60. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
  61. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
  62. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
  63. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
  64. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
  65. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
  66. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
  67. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +1083 -0
  68. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
  69. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
  70. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
  71. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
  72. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
  73. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
  74. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
  75. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
  76. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
  77. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
  78. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
  79. data/ext/nutcracker/m4/libtool.m4 +1474 -1087
  80. data/ext/nutcracker/m4/ltoptions.m4 +90 -37
  81. data/ext/nutcracker/m4/ltsugar.m4 +4 -3
  82. data/ext/nutcracker/m4/ltversion.m4 +6 -6
  83. data/ext/nutcracker/m4/lt~obsolete.m4 +4 -3
  84. data/ext/nutcracker/man/nutcracker.8 +1 -1
  85. data/ext/nutcracker/notes/memcache.md +162 -0
  86. data/ext/nutcracker/notes/recommendation.md +10 -5
  87. data/ext/nutcracker/notes/redis.md +23 -9
  88. data/ext/nutcracker/scripts/nutcracker.init +10 -0
  89. data/ext/nutcracker/scripts/nutcracker.init.debian +83 -0
  90. data/ext/nutcracker/scripts/nutcracker.spec +36 -2
  91. data/ext/nutcracker/scripts/redis-check.sh +4 -0
  92. data/ext/nutcracker/src/Makefile.am +6 -1
  93. data/ext/nutcracker/src/Makefile.in +26 -12
  94. data/ext/nutcracker/src/event/Makefile.in +19 -6
  95. data/ext/nutcracker/src/hashkit/Makefile.in +19 -6
  96. data/ext/nutcracker/src/hashkit/nc_jenkins.c +1 -1
  97. data/ext/nutcracker/src/hashkit/nc_ketama.c +3 -3
  98. data/ext/nutcracker/src/nc.c +1 -1
  99. data/ext/nutcracker/src/nc_conf.c +67 -19
  100. data/ext/nutcracker/src/nc_conf.h +9 -4
  101. data/ext/nutcracker/src/nc_connection.c +35 -2
  102. data/ext/nutcracker/src/nc_connection.h +53 -47
  103. data/ext/nutcracker/src/nc_core.c +8 -1
  104. data/ext/nutcracker/src/nc_message.c +23 -7
  105. data/ext/nutcracker/src/nc_message.h +24 -1
  106. data/ext/nutcracker/src/nc_proxy.c +14 -3
  107. data/ext/nutcracker/src/nc_rbtree.c +1 -5
  108. data/ext/nutcracker/src/nc_request.c +58 -10
  109. data/ext/nutcracker/src/nc_response.c +27 -4
  110. data/ext/nutcracker/src/nc_server.c +33 -5
  111. data/ext/nutcracker/src/nc_server.h +10 -9
  112. data/ext/nutcracker/src/nc_string.h +17 -0
  113. data/ext/nutcracker/src/nc_util.c +5 -1
  114. data/ext/nutcracker/src/proto/Makefile.in +19 -6
  115. data/ext/nutcracker/src/proto/nc_memcache.c +76 -12
  116. data/ext/nutcracker/src/proto/nc_proto.h +9 -0
  117. data/ext/nutcracker/src/proto/nc_redis.c +400 -18
  118. data/lib/nutcracker.rb +1 -1
  119. data/lib/nutcracker/version.rb +1 -1
  120. metadata +61 -6
  121. data/ext/nutcracker/notes/memcache.txt +0 -123
@@ -70,13 +70,12 @@ struct server {
70
70
  uint32_t idx; /* server index */
71
71
  struct server_pool *owner; /* owner pool */
72
72
 
73
- struct string pname; /* name:port:weight (ref in conf_server) */
74
- struct string name; /* name (ref in conf_server) */
73
+ struct string pname; /* hostname:port:weight (ref in conf_server) */
74
+ struct string name; /* hostname:port or [name] (ref in conf_server) */
75
+ struct string addrstr; /* hostname (ref in conf_server) */
75
76
  uint16_t port; /* port */
76
77
  uint32_t weight; /* weight */
77
- int family; /* socket family */
78
- socklen_t addrlen; /* socket length */
79
- struct sockaddr *addr; /* socket address (ref in conf_server) */
78
+ struct sockinfo info; /* server socket info */
80
79
 
81
80
  uint32_t ns_conn_q; /* # server connection */
82
81
  struct conn_tqh s_conn_q; /* server connection q */
@@ -101,21 +100,23 @@ struct server_pool {
101
100
  int64_t next_rebuild; /* next distribution rebuild time in usec */
102
101
 
103
102
  struct string name; /* pool name (ref in conf_pool) */
104
- struct string addrstr; /* pool address (ref in conf_pool) */
103
+ struct string addrstr; /* pool address - hostname:port (ref in conf_pool) */
105
104
  uint16_t port; /* port */
106
- int family; /* socket family */
107
- socklen_t addrlen; /* socket length */
108
- struct sockaddr *addr; /* socket address (ref in conf_pool) */
105
+ struct sockinfo info; /* listen socket info */
106
+ mode_t perm; /* socket permission */
109
107
  int dist_type; /* distribution type (dist_type_t) */
110
108
  int key_hash_type; /* key hash type (hash_type_t) */
111
109
  hash_t key_hash; /* key hasher */
112
110
  struct string hash_tag; /* key hash tag (ref in conf_pool) */
113
111
  int timeout; /* timeout in msec */
114
112
  int backlog; /* listen backlog */
113
+ int redis_db; /* redis database to connect to */
115
114
  uint32_t client_connections; /* maximum # client connection */
116
115
  uint32_t server_connections; /* maximum # server connection */
117
116
  int64_t server_retry_timeout; /* server retry timeout in usec */
118
117
  uint32_t server_failure_limit; /* server failure limit */
118
+ struct string redis_auth; /* redis_auth password (matches requirepass on redis) */
119
+ unsigned require_auth; /* require_auth? */
119
120
  unsigned auto_eject_hosts:1; /* auto_eject_hosts? */
120
121
  unsigned preconnect:1; /* preconnect? */
121
122
  unsigned redis:1; /* redis? */
@@ -77,12 +77,29 @@ int string_compare(const struct string *s1, const struct string *s2);
77
77
  #define nc_strndup(_s, _n) \
78
78
  (uint8_t *)strndup((char *)(_s), (size_t)(_n));
79
79
 
80
+ /*
81
+ * snprintf(s, n, ...) will write at most n - 1 of the characters printed into
82
+ * the output string; the nth character then gets the terminating `\0'; if
83
+ * the return value is greater than or equal to the n argument, the string
84
+ * was too short and some of the printed characters were discarded; the output
85
+ * is always null-terminated.
86
+ *
87
+ * Note that, the return value of snprintf() is always the number of characters
88
+ * that would be printed into the output string, assuming n were limited not
89
+ * including the trailing `\0' used to end output.
90
+ *
91
+ * scnprintf(s, n, ...) is same as snprintf() except, it returns the number
92
+ * of characters printed into the output string not including the trailing '\0'
93
+ */
80
94
  #define nc_snprintf(_s, _n, ...) \
81
95
  snprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
82
96
 
83
97
  #define nc_scnprintf(_s, _n, ...) \
84
98
  _scnprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
85
99
 
100
+ #define nc_vsnprintf(_s, _n, _f, _a) \
101
+ vsnprintf((char *)(_s), (size_t)(_n), _f, _a)
102
+
86
103
  #define nc_vscnprintf(_s, _n, _f, _a) \
87
104
  _vscnprintf((char *)(_s), (size_t)(_n), _f, _a)
88
105
 
@@ -489,8 +489,12 @@ nc_resolve_inet(struct string *name, int port, struct sockinfo *si)
489
489
 
490
490
  nc_snprintf(service, NC_UINTMAX_MAXLEN, "%d", port);
491
491
 
492
+ /*
493
+ * getaddrinfo() returns zero on success or one of the error codes listed
494
+ * in gai_strerror(3) if an error occurs
495
+ */
492
496
  status = getaddrinfo(node, service, &hints, &ai);
493
- if (status < 0) {
497
+ if (status != 0) {
494
498
  log_error("address resolution of node '%s' service '%s' failed: %s",
495
499
  node, service, gai_strerror(status));
496
500
  return -1;
@@ -1,7 +1,7 @@
1
- # Makefile.in generated by automake 1.14.1 from Makefile.am.
1
+ # Makefile.in generated by automake 1.15 from Makefile.am.
2
2
  # @configure_input@
3
3
 
4
- # Copyright (C) 1994-2013 Free Software Foundation, Inc.
4
+ # Copyright (C) 1994-2014 Free Software Foundation, Inc.
5
5
 
6
6
  # This Makefile.in is free software; the Free Software Foundation
7
7
  # gives unlimited permission to copy and/or distribute it,
@@ -16,7 +16,17 @@
16
16
 
17
17
 
18
18
  VPATH = @srcdir@
19
- am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
19
+ am__is_gnu_make = { \
20
+ if test -z '$(MAKELEVEL)'; then \
21
+ false; \
22
+ elif test -n '$(MAKE_HOST)'; then \
23
+ true; \
24
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
25
+ true; \
26
+ else \
27
+ false; \
28
+ fi; \
29
+ }
20
30
  am__make_running_with_option = \
21
31
  case $${target_option-} in \
22
32
  ?) ;; \
@@ -80,8 +90,6 @@ POST_UNINSTALL = :
80
90
  build_triplet = @build@
81
91
  host_triplet = @host@
82
92
  subdir = src/proto
83
- DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
84
- $(top_srcdir)/config/depcomp $(noinst_HEADERS)
85
93
  ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
86
94
  am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
87
95
  $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
@@ -89,6 +97,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
89
97
  $(top_srcdir)/configure.ac
90
98
  am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
91
99
  $(ACLOCAL_M4)
100
+ DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
101
+ $(am__DIST_COMMON)
92
102
  mkinstalldirs = $(install_sh) -d
93
103
  CONFIG_HEADER = $(top_builddir)/config.h
94
104
  CONFIG_CLEAN_FILES =
@@ -168,6 +178,7 @@ am__define_uniq_tagged_files = \
168
178
  done | $(am__uniquify_input)`
169
179
  ETAGS = etags
170
180
  CTAGS = ctags
181
+ am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp
171
182
  DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
172
183
  ACLOCAL = @ACLOCAL@
173
184
  AMTAR = @AMTAR@
@@ -212,6 +223,7 @@ LIBTOOL = @LIBTOOL@
212
223
  LIPO = @LIPO@
213
224
  LN_S = @LN_S@
214
225
  LTLIBOBJS = @LTLIBOBJS@
226
+ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
215
227
  MAKEINFO = @MAKEINFO@
216
228
  MANIFEST_TOOL = @MANIFEST_TOOL@
217
229
  MKDIR_P = @MKDIR_P@
@@ -314,7 +326,6 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
314
326
  echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/proto/Makefile'; \
315
327
  $(am__cd) $(top_srcdir) && \
316
328
  $(AUTOMAKE) --foreign src/proto/Makefile
317
- .PRECIOUS: Makefile
318
329
  Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
319
330
  @case '$?' in \
320
331
  *config.status*) \
@@ -581,6 +592,8 @@ uninstall-am:
581
592
  mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
582
593
  tags tags-am uninstall uninstall-am
583
594
 
595
+ .PRECIOUS: Makefile
596
+
584
597
 
585
598
  # Tell versions [3.59,3.63) of GNU make to not export all variables.
586
599
  # Otherwise a system limit (for SysV at least) may be exceeded.
@@ -121,6 +121,20 @@ memcache_delete(struct msg *r)
121
121
  return false;
122
122
  }
123
123
 
124
+ /*
125
+ * Return true, if the memcache command is a touch command, otherwise
126
+ * return false
127
+ */
128
+ static bool
129
+ memcache_touch(struct msg *r)
130
+ {
131
+ if (r->type == MSG_REQ_MC_TOUCH) {
132
+ return true;
133
+ }
134
+
135
+ return false;
136
+ }
137
+
124
138
  void
125
139
  memcache_parse_req(struct msg *r)
126
140
  {
@@ -243,6 +257,14 @@ memcache_parse_req(struct msg *r)
243
257
 
244
258
  break;
245
259
 
260
+ case 5:
261
+ if (str5cmp(m, 't', 'o', 'u', 'c', 'h')) {
262
+ r->type = MSG_REQ_MC_TOUCH;
263
+ break;
264
+ }
265
+
266
+ break;
267
+
246
268
  case 6:
247
269
  if (str6cmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) {
248
270
  r->type = MSG_REQ_MC_APPEND;
@@ -282,6 +304,7 @@ memcache_parse_req(struct msg *r)
282
304
  case MSG_REQ_MC_PREPEND:
283
305
  case MSG_REQ_MC_INCR:
284
306
  case MSG_REQ_MC_DECR:
307
+ case MSG_REQ_MC_TOUCH:
285
308
  if (ch == CR) {
286
309
  goto error;
287
310
  }
@@ -320,13 +343,17 @@ memcache_parse_req(struct msg *r)
320
343
  }
321
344
  if (ch == ' ' || ch == CR) {
322
345
  struct keypos *kpos;
323
-
324
- if ((p - r->token) > MEMCACHE_MAX_KEY_LENGTH) {
346
+ int keylen = p - r->token;
347
+ if (keylen > MEMCACHE_MAX_KEY_LENGTH) {
325
348
  log_error("parsed bad req %"PRIu64" of type %d with key "
326
349
  "prefix '%.*s...' and length %d that exceeds "
327
350
  "maximum key length", r->id, r->type, 16,
328
351
  r->token, p - r->token);
329
352
  goto error;
353
+ } else if (keylen == 0) {
354
+ log_error("parsed bad req %"PRIu64" of type %d with an "
355
+ "empty key", r->id, r->type);
356
+ goto error;
330
357
  }
331
358
 
332
359
  kpos = array_push(r->keys);
@@ -342,7 +369,7 @@ memcache_parse_req(struct msg *r)
342
369
  /* get next state */
343
370
  if (memcache_storage(r)) {
344
371
  state = SW_SPACES_BEFORE_FLAGS;
345
- } else if (memcache_arithmetic(r)) {
372
+ } else if (memcache_arithmetic(r) || memcache_touch(r) ) {
346
373
  state = SW_SPACES_BEFORE_NUM;
347
374
  } else if (memcache_delete(r)) {
348
375
  state = SW_RUNTO_CRLF;
@@ -531,7 +558,7 @@ memcache_parse_req(struct msg *r)
531
558
 
532
559
  case SW_SPACES_BEFORE_NUM:
533
560
  if (ch != ' ') {
534
- if (!isdigit(ch)) {
561
+ if (!(isdigit(ch) || ch == '-')) {
535
562
  goto error;
536
563
  }
537
564
  /* num_start <- p; num <- ch - '0' */
@@ -562,7 +589,7 @@ memcache_parse_req(struct msg *r)
562
589
  break;
563
590
 
564
591
  case 'n':
565
- if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r)) {
592
+ if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r) || memcache_touch(r)) {
566
593
  /* noreply_start <- p */
567
594
  r->token = p;
568
595
  state = SW_NOREPLY;
@@ -593,7 +620,7 @@ memcache_parse_req(struct msg *r)
593
620
  case CR:
594
621
  m = r->token;
595
622
  if (((p - m) == 7) && str7cmp(m, 'n', 'o', 'r', 'e', 'p', 'l', 'y')) {
596
- ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r));
623
+ ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r) || memcache_touch(r));
597
624
  r->token = NULL;
598
625
  /* noreply_end <- p - 1 */
599
626
  r->noreply = 1;
@@ -854,6 +881,11 @@ memcache_parse_rsp(struct msg *r)
854
881
  break;
855
882
  }
856
883
 
884
+ if (str7cmp(m, 'T', 'O', 'U', 'C', 'H', 'E', 'D')) {
885
+ r->type = MSG_RSP_MC_TOUCHED;
886
+ break;
887
+ }
888
+
857
889
  break;
858
890
 
859
891
  case 9:
@@ -895,6 +927,7 @@ memcache_parse_rsp(struct msg *r)
895
927
  case MSG_RSP_MC_EXISTS:
896
928
  case MSG_RSP_MC_NOT_FOUND:
897
929
  case MSG_RSP_MC_DELETED:
930
+ case MSG_RSP_MC_TOUCHED:
898
931
  state = SW_CRLF;
899
932
  break;
900
933
 
@@ -1167,6 +1200,12 @@ error:
1167
1200
  r->state);
1168
1201
  }
1169
1202
 
1203
+ bool
1204
+ memcache_failure(struct msg *r)
1205
+ {
1206
+ return false;
1207
+ }
1208
+
1170
1209
  static rstatus_t
1171
1210
  memcache_append_key(struct msg *r, uint8_t *key, uint32_t keylen)
1172
1211
  {
@@ -1377,9 +1416,8 @@ memcache_pre_coalesce(struct msg *r)
1377
1416
  }
1378
1417
 
1379
1418
  /*
1380
- * copy one response from src to dst
1381
- * return bytes copied
1382
- * */
1419
+ * Copy one response from src to dst and return bytes copied
1420
+ */
1383
1421
  static rstatus_t
1384
1422
  memcache_copy_bulk(struct msg *dst, struct msg *src)
1385
1423
  {
@@ -1403,9 +1441,10 @@ memcache_copy_bulk(struct msg *dst, struct msg *src)
1403
1441
  }
1404
1442
  p = mbuf->pos;
1405
1443
 
1406
- /* get : VALUE key 0 len\r\nval\r\n */
1407
- /* gets: VALUE key 0 len cas\r\nval\r\n */
1408
-
1444
+ /*
1445
+ * get : VALUE key 0 len\r\nval\r\n
1446
+ * gets: VALUE key 0 len cas\r\nval\r\n
1447
+ */
1409
1448
  ASSERT(*p == 'V');
1410
1449
  for (i = 0; i < 3; i++) { /* eat 'VALUE key 0 ' */
1411
1450
  for (; *p != ' ';) {
@@ -1495,3 +1534,28 @@ memcache_post_coalesce(struct msg *request)
1495
1534
  return;
1496
1535
  }
1497
1536
  }
1537
+
1538
+ void
1539
+ memcache_post_connect(struct context *ctx, struct conn *conn, struct server *server)
1540
+ {
1541
+ }
1542
+
1543
+ void
1544
+ memcache_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg)
1545
+ {
1546
+ }
1547
+
1548
+ rstatus_t
1549
+ memcache_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn)
1550
+ {
1551
+ NOT_REACHED();
1552
+ return NC_OK;
1553
+ }
1554
+
1555
+ rstatus_t
1556
+ memcache_reply(struct msg *r)
1557
+ {
1558
+ NOT_REACHED();
1559
+ return NC_OK;
1560
+ }
1561
+
@@ -140,15 +140,24 @@
140
140
 
141
141
  void memcache_parse_req(struct msg *r);
142
142
  void memcache_parse_rsp(struct msg *r);
143
+ bool memcache_failure(struct msg *r);
143
144
  void memcache_pre_coalesce(struct msg *r);
144
145
  void memcache_post_coalesce(struct msg *r);
146
+ rstatus_t memcache_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn);
145
147
  rstatus_t memcache_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq);
148
+ rstatus_t memcache_reply(struct msg *r);
149
+ void memcache_post_connect(struct context *ctx, struct conn *conn, struct server *server);
150
+ void memcache_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg);
146
151
 
147
152
  void redis_parse_req(struct msg *r);
148
153
  void redis_parse_rsp(struct msg *r);
154
+ bool redis_failure(struct msg *r);
149
155
  void redis_pre_coalesce(struct msg *r);
150
156
  void redis_post_coalesce(struct msg *r);
157
+ rstatus_t redis_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn);
151
158
  rstatus_t redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq);
152
159
  rstatus_t redis_reply(struct msg *r);
160
+ void redis_post_connect(struct context *ctx, struct conn *conn, struct server *server);
161
+ void redis_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg);
153
162
 
154
163
  #endif
@@ -17,10 +17,24 @@
17
17
 
18
18
  #include <stdio.h>
19
19
  #include <ctype.h>
20
+ #include <math.h>
20
21
 
21
22
  #include <nc_core.h>
22
23
  #include <nc_proto.h>
23
24
 
25
+ #define RSP_STRING(ACTION) \
26
+ ACTION( ok, "+OK\r\n" ) \
27
+ ACTION( pong, "+PONG\r\n" ) \
28
+ ACTION( invalid_password, "-ERR invalid password\r\n" ) \
29
+ ACTION( auth_required, "-NOAUTH Authentication required\r\n" ) \
30
+ ACTION( no_password, "-ERR Client sent AUTH, but no password is set\r\n" ) \
31
+
32
+ #define DEFINE_ACTION(_var, _str) static struct string rsp_##_var = string(_str);
33
+ RSP_STRING( DEFINE_ACTION )
34
+ #undef DEFINE_ACTION
35
+
36
+ static rstatus_t redis_handle_auth_req(struct msg *request, struct msg *response);
37
+
24
38
  /*
25
39
  * Return true, if the redis command take no key, otherwise
26
40
  * return false
@@ -51,7 +65,6 @@ redis_arg0(struct msg *r)
51
65
  case MSG_REQ_REDIS_EXISTS:
52
66
  case MSG_REQ_REDIS_PERSIST:
53
67
  case MSG_REQ_REDIS_PTTL:
54
- case MSG_REQ_REDIS_SORT:
55
68
  case MSG_REQ_REDIS_TTL:
56
69
  case MSG_REQ_REDIS_TYPE:
57
70
  case MSG_REQ_REDIS_DUMP:
@@ -75,8 +88,8 @@ redis_arg0(struct msg *r)
75
88
  case MSG_REQ_REDIS_SPOP:
76
89
 
77
90
  case MSG_REQ_REDIS_ZCARD:
78
-
79
91
  case MSG_REQ_REDIS_PFCOUNT:
92
+ case MSG_REQ_REDIS_AUTH:
80
93
  return true;
81
94
 
82
95
  default:
@@ -198,6 +211,8 @@ static bool
198
211
  redis_argn(struct msg *r)
199
212
  {
200
213
  switch (r->type) {
214
+ case MSG_REQ_REDIS_SORT:
215
+
201
216
  case MSG_REQ_REDIS_BITCOUNT:
202
217
 
203
218
  case MSG_REQ_REDIS_SET:
@@ -300,6 +315,37 @@ redis_argeval(struct msg *r)
300
315
  return false;
301
316
  }
302
317
 
318
+ /*
319
+ * Return true, if the redis response is an error response i.e. a simple
320
+ * string whose first character is '-', otherwise return false.
321
+ */
322
+ static bool
323
+ redis_error(struct msg *r)
324
+ {
325
+ switch (r->type) {
326
+ case MSG_RSP_REDIS_ERROR:
327
+ case MSG_RSP_REDIS_ERROR_ERR:
328
+ case MSG_RSP_REDIS_ERROR_OOM:
329
+ case MSG_RSP_REDIS_ERROR_BUSY:
330
+ case MSG_RSP_REDIS_ERROR_NOAUTH:
331
+ case MSG_RSP_REDIS_ERROR_LOADING:
332
+ case MSG_RSP_REDIS_ERROR_BUSYKEY:
333
+ case MSG_RSP_REDIS_ERROR_MISCONF:
334
+ case MSG_RSP_REDIS_ERROR_NOSCRIPT:
335
+ case MSG_RSP_REDIS_ERROR_READONLY:
336
+ case MSG_RSP_REDIS_ERROR_WRONGTYPE:
337
+ case MSG_RSP_REDIS_ERROR_EXECABORT:
338
+ case MSG_RSP_REDIS_ERROR_MASTERDOWN:
339
+ case MSG_RSP_REDIS_ERROR_NOREPLICAS:
340
+ return true;
341
+
342
+ default:
343
+ break;
344
+ }
345
+
346
+ return false;
347
+ }
348
+
303
349
  /*
304
350
  * Reference: http://redis.io/topics/protocol
305
351
  *
@@ -625,6 +671,12 @@ redis_parse_req(struct msg *r)
625
671
  break;
626
672
  }
627
673
 
674
+ if (str4icmp(m, 'a', 'u', 't', 'h')) {
675
+ r->type = MSG_REQ_REDIS_AUTH;
676
+ r->noforward = 1;
677
+ break;
678
+ }
679
+
628
680
  break;
629
681
 
630
682
  case 5:
@@ -1051,6 +1103,8 @@ redis_parse_req(struct msg *r)
1051
1103
  case LF:
1052
1104
  if (redis_argz(r)) {
1053
1105
  goto done;
1106
+ } else if (r->narg == 1) {
1107
+ goto error;
1054
1108
  } else if (redis_argeval(r)) {
1055
1109
  state = SW_ARG1_LEN;
1056
1110
  } else {
@@ -1074,11 +1128,6 @@ redis_parse_req(struct msg *r)
1074
1128
  } else if (isdigit(ch)) {
1075
1129
  r->rlen = r->rlen * 10 + (uint32_t)(ch - '0');
1076
1130
  } else if (ch == CR) {
1077
- if (r->rlen == 0) {
1078
- log_error("parsed bad req %"PRIu64" of type %d with empty "
1079
- "key", r->id, r->type);
1080
- goto error;
1081
- }
1082
1131
  if (r->rlen >= mbuf_data_size()) {
1083
1132
  log_error("parsed bad req %"PRIu64" of type %d with key "
1084
1133
  "length %d that greater than or equal to maximum"
@@ -1178,8 +1227,8 @@ redis_parse_req(struct msg *r)
1178
1227
  }
1179
1228
  state = SW_KEY_LEN;
1180
1229
  } else if (redis_argkvx(r)) {
1181
- if (r->rnarg == 0) {
1182
- goto done;
1230
+ if (r->narg % 2 == 0) {
1231
+ goto error;
1183
1232
  }
1184
1233
  state = SW_ARG1_LEN;
1185
1234
  } else if (redis_argeval(r)) {
@@ -1672,6 +1721,7 @@ redis_parse_rsp(struct msg *r)
1672
1721
  SW_ERROR,
1673
1722
  SW_INTEGER,
1674
1723
  SW_INTEGER_START,
1724
+ SW_SIMPLE,
1675
1725
  SW_BULK,
1676
1726
  SW_BULK_LF,
1677
1727
  SW_BULK_ARG,
@@ -1748,8 +1798,125 @@ redis_parse_rsp(struct msg *r)
1748
1798
  break;
1749
1799
 
1750
1800
  case SW_ERROR:
1751
- /* rsp_start <- p */
1752
- state = SW_RUNTO_CRLF;
1801
+ if (r->token == NULL) {
1802
+ if (ch != '-') {
1803
+ goto error;
1804
+ }
1805
+ /* rsp_start <- p */
1806
+ r->token = p;
1807
+ }
1808
+ if (ch == ' ' || ch == CR) {
1809
+ m = r->token;
1810
+ r->token = NULL;
1811
+ switch (p - m) {
1812
+
1813
+ case 4:
1814
+ /*
1815
+ * -ERR no such key\r\n
1816
+ * -ERR syntax error\r\n
1817
+ * -ERR source and destination objects are the same\r\n
1818
+ * -ERR index out of range\r\n
1819
+ */
1820
+ if (str4cmp(m, '-', 'E', 'R', 'R')) {
1821
+ r->type = MSG_RSP_REDIS_ERROR_ERR;
1822
+ break;
1823
+ }
1824
+
1825
+ /* -OOM command not allowed when used memory > 'maxmemory'.\r\n */
1826
+ if (str4cmp(m, '-', 'O', 'O', 'M')) {
1827
+ r->type = MSG_RSP_REDIS_ERROR_OOM;
1828
+ break;
1829
+ }
1830
+
1831
+ break;
1832
+
1833
+ case 5:
1834
+ /* -BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.\r\n" */
1835
+ if (str5cmp(m, '-', 'B', 'U', 'S', 'Y')) {
1836
+ r->type = MSG_RSP_REDIS_ERROR_BUSY;
1837
+ break;
1838
+ }
1839
+
1840
+ break;
1841
+
1842
+ case 7:
1843
+ /* -NOAUTH Authentication required.\r\n */
1844
+ if (str7cmp(m, '-', 'N', 'O', 'A', 'U', 'T', 'H')) {
1845
+ r->type = MSG_RSP_REDIS_ERROR_NOAUTH;
1846
+ break;
1847
+ }
1848
+
1849
+ break;
1850
+
1851
+ case 8:
1852
+ /* rsp: "-LOADING Redis is loading the dataset in memory\r\n" */
1853
+ if (str8cmp(m, '-', 'L', 'O', 'A', 'D', 'I', 'N', 'G')) {
1854
+ r->type = MSG_RSP_REDIS_ERROR_LOADING;
1855
+ break;
1856
+ }
1857
+
1858
+ /* -BUSYKEY Target key name already exists.\r\n */
1859
+ if (str8cmp(m, '-', 'B', 'U', 'S', 'Y', 'K', 'E', 'Y')) {
1860
+ r->type = MSG_RSP_REDIS_ERROR_BUSYKEY;
1861
+ break;
1862
+ }
1863
+
1864
+ /* "-MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.\r\n" */
1865
+ if (str8cmp(m, '-', 'M', 'I', 'S', 'C', 'O', 'N', 'F')) {
1866
+ r->type = MSG_RSP_REDIS_ERROR_MISCONF;
1867
+ break;
1868
+ }
1869
+
1870
+ break;
1871
+
1872
+ case 9:
1873
+ /* -NOSCRIPT No matching script. Please use EVAL.\r\n */
1874
+ if (str9cmp(m, '-', 'N', 'O', 'S', 'C', 'R', 'I', 'P', 'T')) {
1875
+ r->type = MSG_RSP_REDIS_ERROR_NOSCRIPT;
1876
+ break;
1877
+ }
1878
+
1879
+ /* -READONLY You can't write against a read only slave.\r\n */
1880
+ if (str9cmp(m, '-', 'R', 'E', 'A', 'D', 'O', 'N', 'L', 'Y')) {
1881
+ r->type = MSG_RSP_REDIS_ERROR_READONLY;
1882
+ break;
1883
+ }
1884
+
1885
+ break;
1886
+
1887
+ case 10:
1888
+ /* -WRONGTYPE Operation against a key holding the wrong kind of value\r\n */
1889
+ if (str10cmp(m, '-', 'W', 'R', 'O', 'N', 'G', 'T', 'Y', 'P', 'E')) {
1890
+ r->type = MSG_RSP_REDIS_ERROR_WRONGTYPE;
1891
+ break;
1892
+ }
1893
+
1894
+ /* -EXECABORT Transaction discarded because of previous errors.\r\n" */
1895
+ if (str10cmp(m, '-', 'E', 'X', 'E', 'C', 'A', 'B', 'O', 'R', 'T')) {
1896
+ r->type = MSG_RSP_REDIS_ERROR_EXECABORT;
1897
+ break;
1898
+ }
1899
+
1900
+ break;
1901
+
1902
+ case 11:
1903
+ /* -MASTERDOWN Link with MASTER is down and slave-serve-stale-data is set to 'no'.\r\n */
1904
+ if (str11cmp(m, '-', 'M', 'A', 'S', 'T', 'E', 'R', 'D', 'O', 'W', 'N')) {
1905
+ r->type = MSG_RSP_REDIS_ERROR_MASTERDOWN;
1906
+ break;
1907
+ }
1908
+
1909
+ /* -NOREPLICAS Not enough good slaves to write.\r\n */
1910
+ if (str11cmp(m, '-', 'N', 'O', 'R', 'E', 'P', 'L', 'I', 'C', 'A', 'S')) {
1911
+ r->type = MSG_RSP_REDIS_ERROR_NOREPLICAS;
1912
+ break;
1913
+ }
1914
+
1915
+ break;
1916
+ }
1917
+ state = SW_RUNTO_CRLF;
1918
+ }
1919
+
1753
1920
  break;
1754
1921
 
1755
1922
  case SW_INTEGER:
@@ -1758,6 +1925,13 @@ redis_parse_rsp(struct msg *r)
1758
1925
  r->integer = 0;
1759
1926
  break;
1760
1927
 
1928
+ case SW_SIMPLE:
1929
+ if (ch == CR) {
1930
+ state = SW_MULTIBULK_ARGN_LF;
1931
+ r->rnarg--;
1932
+ }
1933
+ break;
1934
+
1761
1935
  case SW_INTEGER_START:
1762
1936
  if (ch == CR) {
1763
1937
  state = SW_ALMOST_DONE;
@@ -1897,6 +2071,7 @@ redis_parse_rsp(struct msg *r)
1897
2071
  /* response is '*0\r\n' */
1898
2072
  goto done;
1899
2073
  }
2074
+
1900
2075
  state = SW_MULTIBULK_ARGN_LEN;
1901
2076
  break;
1902
2077
 
@@ -1938,9 +2113,17 @@ redis_parse_rsp(struct msg *r)
1938
2113
  break;
1939
2114
  }
1940
2115
 
1941
- if (ch != '$' && ch != ':') {
2116
+ if (ch == ':' || ch == '+' || ch == '-') {
2117
+ /* handles not-found reply = '$-1' or integer reply = ':<num>' */
2118
+ /* and *2\r\n$2\r\nr0\r\n+OK\r\n or *1\r\n+OK\r\n */
2119
+ state = SW_SIMPLE;
2120
+ break;
2121
+ }
2122
+
2123
+ if (ch != '$') {
1942
2124
  goto error;
1943
2125
  }
2126
+
1944
2127
  r->token = p;
1945
2128
  r->rlen = 0;
1946
2129
  } else if (isdigit(ch)) {
@@ -1952,8 +2135,7 @@ redis_parse_rsp(struct msg *r)
1952
2135
  goto error;
1953
2136
  }
1954
2137
 
1955
- if ((r->rlen == 1 && (p - r->token) == 3) || *r->token == ':') {
1956
- /* handles not-found reply = '$-1' or integer reply = ':<num>' */
2138
+ if ((r->rlen == 1 && (p - r->token) == 3)) {
1957
2139
  r->rlen = 0;
1958
2140
  state = SW_MULTIBULK_ARGN_LF;
1959
2141
  } else {
@@ -2062,6 +2244,37 @@ error:
2062
2244
  r->state);
2063
2245
  }
2064
2246
 
2247
+ /*
2248
+ * Return true, if redis replies with a transient server failure response,
2249
+ * otherwise return false
2250
+ *
2251
+ * Transient failures on redis are scenarios when it is temporarily
2252
+ * unresponsive and responds with the following protocol specific error
2253
+ * reply:
2254
+ * -OOM, when redis is out-of-memory
2255
+ * -BUSY, when redis is busy
2256
+ * -LOADING when redis is loading dataset into memory
2257
+ *
2258
+ * See issue: https://github.com/twitter/twemproxy/issues/369
2259
+ */
2260
+ bool
2261
+ redis_failure(struct msg *r)
2262
+ {
2263
+ ASSERT(!r->request);
2264
+
2265
+ switch (r->type) {
2266
+ case MSG_RSP_REDIS_ERROR_OOM:
2267
+ case MSG_RSP_REDIS_ERROR_BUSY:
2268
+ case MSG_RSP_REDIS_ERROR_LOADING:
2269
+ return true;
2270
+
2271
+ default:
2272
+ break;
2273
+ }
2274
+
2275
+ return false;
2276
+ }
2277
+
2065
2278
  /*
2066
2279
  * copy one bulk from src to dst
2067
2280
  *
@@ -2443,8 +2656,10 @@ redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq)
2443
2656
  case MSG_REQ_REDIS_MGET:
2444
2657
  case MSG_REQ_REDIS_DEL:
2445
2658
  return redis_fragment_argx(r, ncontinuum, frag_msgq, 1);
2659
+
2446
2660
  case MSG_REQ_REDIS_MSET:
2447
2661
  return redis_fragment_argx(r, ncontinuum, frag_msgq, 2);
2662
+
2448
2663
  default:
2449
2664
  return NC_OK;
2450
2665
  }
@@ -2453,13 +2668,23 @@ redis_fragment(struct msg *r, uint32_t ncontinuum, struct msg_tqh *frag_msgq)
2453
2668
  rstatus_t
2454
2669
  redis_reply(struct msg *r)
2455
2670
  {
2671
+ struct conn *c_conn;
2456
2672
  struct msg *response = r->peer;
2457
2673
 
2458
- ASSERT(response != NULL);
2674
+ ASSERT(response != NULL && response->owner != NULL);
2675
+
2676
+ c_conn = response->owner;
2677
+ if (r->type == MSG_REQ_REDIS_AUTH) {
2678
+ return redis_handle_auth_req(r, response);
2679
+ }
2680
+
2681
+ if (!conn_authenticated(c_conn)) {
2682
+ return msg_append(response, rsp_auth_required.data, rsp_auth_required.len);
2683
+ }
2459
2684
 
2460
2685
  switch (r->type) {
2461
2686
  case MSG_REQ_REDIS_PING:
2462
- return msg_append(response, (uint8_t *)"+PONG\r\n", 7);
2687
+ return msg_append(response, rsp_pong.data, rsp_pong.len);
2463
2688
 
2464
2689
  default:
2465
2690
  NOT_REACHED();
@@ -2470,10 +2695,10 @@ redis_reply(struct msg *r)
2470
2695
  void
2471
2696
  redis_post_coalesce_mset(struct msg *request)
2472
2697
  {
2473
- struct msg *response = request->peer;
2474
2698
  rstatus_t status;
2699
+ struct msg *response = request->peer;
2475
2700
 
2476
- status = msg_append(response, (uint8_t *)"+OK\r\n", 5);
2701
+ status = msg_append(response, rsp_ok.data, rsp_ok.len);
2477
2702
  if (status != NC_OK) {
2478
2703
  response->error = 1; /* mark this msg as err */
2479
2704
  response->err = errno;
@@ -2546,11 +2771,168 @@ redis_post_coalesce(struct msg *r)
2546
2771
  switch (r->type) {
2547
2772
  case MSG_REQ_REDIS_MGET:
2548
2773
  return redis_post_coalesce_mget(r);
2774
+
2549
2775
  case MSG_REQ_REDIS_DEL:
2550
2776
  return redis_post_coalesce_del(r);
2777
+
2551
2778
  case MSG_REQ_REDIS_MSET:
2552
2779
  return redis_post_coalesce_mset(r);
2780
+
2553
2781
  default:
2554
2782
  NOT_REACHED();
2555
2783
  }
2556
2784
  }
2785
+
2786
+ static rstatus_t
2787
+ redis_handle_auth_req(struct msg *req, struct msg *rsp)
2788
+ {
2789
+ struct conn *conn = (struct conn *)rsp->owner;
2790
+ struct server_pool *pool;
2791
+ struct keypos *kpos;
2792
+ uint8_t *key;
2793
+ uint32_t keylen;
2794
+ bool valid;
2795
+
2796
+ ASSERT(conn->client && !conn->proxy);
2797
+
2798
+ pool = (struct server_pool *)conn->owner;
2799
+
2800
+ if (!pool->require_auth) {
2801
+ /*
2802
+ * AUTH command from the client in absence of a redis_auth:
2803
+ * directive should be treated as an error
2804
+ */
2805
+ return msg_append(rsp, rsp_no_password.data, rsp_no_password.len);
2806
+ }
2807
+
2808
+ kpos = array_get(req->keys, 0);
2809
+ key = kpos->start;
2810
+ keylen = (uint32_t)(kpos->end - kpos->start);
2811
+ valid = (keylen == pool->redis_auth.len) &&
2812
+ (memcmp(pool->redis_auth.data, key, keylen) == 0) ? true : false;
2813
+ if (valid) {
2814
+ conn->authenticated = 1;
2815
+ return msg_append(rsp, rsp_ok.data, rsp_ok.len);
2816
+ }
2817
+
2818
+ /*
2819
+ * Password in the AUTH command doesn't match the one configured in
2820
+ * redis_auth: directive
2821
+ *
2822
+ * We mark the connection has unauthenticated until the client
2823
+ * reauthenticates with the correct password
2824
+ */
2825
+ conn->authenticated = 0;
2826
+ return msg_append(rsp, rsp_invalid_password.data, rsp_invalid_password.len);
2827
+ }
2828
+
2829
+ rstatus_t
2830
+ redis_add_auth(struct context *ctx, struct conn *c_conn, struct conn *s_conn)
2831
+ {
2832
+ rstatus_t status;
2833
+ struct msg *msg;
2834
+ struct server_pool *pool;
2835
+
2836
+ ASSERT(!s_conn->client && !s_conn->proxy);
2837
+ ASSERT(!conn_authenticated(s_conn));
2838
+
2839
+ pool = c_conn->owner;
2840
+
2841
+ msg = msg_get(c_conn, true, c_conn->redis);
2842
+ if (msg == NULL) {
2843
+ c_conn->err = errno;
2844
+ return NC_ENOMEM;
2845
+ }
2846
+
2847
+ status = msg_prepend_format(msg, "*2\r\n$4\r\nAUTH\r\n$%d\r\n%s\r\n",
2848
+ pool->redis_auth.len, pool->redis_auth.data);
2849
+ if (status != NC_OK) {
2850
+ msg_put(msg);
2851
+ return status;
2852
+ }
2853
+
2854
+ msg->swallow = 1;
2855
+ s_conn->enqueue_inq(ctx, s_conn, msg);
2856
+ s_conn->authenticated = 1;
2857
+
2858
+ return NC_OK;
2859
+ }
2860
+
2861
+ void
2862
+ redis_post_connect(struct context *ctx, struct conn *conn, struct server *server)
2863
+ {
2864
+ rstatus_t status;
2865
+ struct server_pool *pool = server->owner;
2866
+ struct msg *msg;
2867
+ int digits;
2868
+
2869
+ ASSERT(!conn->client && conn->connected);
2870
+ ASSERT(conn->redis);
2871
+
2872
+ /*
2873
+ * By default, every connection to redis uses the database DB 0. You
2874
+ * can select a different one on a per-connection basis by sending
2875
+ * a request 'SELECT <redis_db>', where <redis_db> is the configured
2876
+ * on a per pool basis in the configuration
2877
+ */
2878
+ if (pool->redis_db <= 0) {
2879
+ return;
2880
+ }
2881
+
2882
+ /*
2883
+ * Create a fake client message and add it to the pipeline. We force this
2884
+ * message to be head of queue as it might already contain a command
2885
+ * that triggered the connect.
2886
+ */
2887
+ msg = msg_get(conn, true, conn->redis);
2888
+ if (msg == NULL) {
2889
+ return;
2890
+ }
2891
+
2892
+ digits = (pool->redis_db >= 10) ? (int)log10(pool->redis_db) + 1 : 1;
2893
+ status = msg_prepend_format(msg, "*2\r\n$6\r\nSELECT\r\n$%d\r\n%d\r\n", digits, pool->redis_db);
2894
+ if (status != NC_OK) {
2895
+ msg_put(msg);
2896
+ return;
2897
+ }
2898
+ msg->type = MSG_REQ_REDIS_SELECT;
2899
+ msg->result = MSG_PARSE_OK;
2900
+ msg->swallow = 1;
2901
+ msg->owner = NULL;
2902
+
2903
+ /* enqueue as head and send */
2904
+ req_server_enqueue_imsgq_head(ctx, conn, msg);
2905
+ msg_send(ctx, conn);
2906
+
2907
+ log_debug(LOG_NOTICE, "sent 'SELECT %d' to %s | %s", pool->redis_db,
2908
+ pool->name.data, server->name.data);
2909
+ }
2910
+
2911
+ void
2912
+ redis_swallow_msg(struct conn *conn, struct msg *pmsg, struct msg *msg)
2913
+ {
2914
+ if (pmsg != NULL && pmsg->type == MSG_REQ_REDIS_SELECT &&
2915
+ msg != NULL && redis_error(msg)) {
2916
+ struct server* conn_server;
2917
+ struct server_pool* conn_pool;
2918
+ struct mbuf* rsp_buffer;
2919
+ uint8_t message[128];
2920
+ size_t copy_len;
2921
+
2922
+ /*
2923
+ * Get a substring from the message so that the inital - and the trailing
2924
+ * \r\n is removed.
2925
+ */
2926
+ conn_server = (struct server*)conn->owner;
2927
+ conn_pool = conn_server->owner;
2928
+ rsp_buffer = STAILQ_LAST(&msg->mhdr, mbuf, next);
2929
+ copy_len = MIN(mbuf_length(rsp_buffer) - 3, sizeof(message) - 1);
2930
+
2931
+ nc_memcpy(message, &rsp_buffer->start[1], copy_len);
2932
+ message[copy_len] = 0;
2933
+
2934
+ log_warn("SELECT %d failed on %s | %s: %s",
2935
+ conn_pool->redis_db, conn_pool->name.data,
2936
+ conn_server->name.data, message);
2937
+ }
2938
+ }