Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
bb_store_redis.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
64 #include "gw-config.h"
65 
66 #include <unistd.h>
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <fcntl.h>
70 #include <dirent.h>
71 #include <errno.h>
72 
73 #include "gwlib/gwlib.h"
74 #include "msg.h"
75 #include "sms.h"
76 #include "bearerbox.h"
77 #include "bb_store.h"
78 
79 #ifdef HAVE_REDIS
80 #include "gwlib/dbpool.h"
81 
82 /*
83  * Define REDIS_TRACE to get DEBUG level output of the
84  * Redis commands send to the server.
85  */
86 /* #define REDIS_TRACE 1 */
87 
88 static Counter *counter;
89 static List *loaded;
90 
91 static DBPool *pool = NULL;
92 
93 struct store_db_fields {
94  Octstr *table;
95  Octstr *field_uuid;
96  Octstr *field_message;
97 };
98 
99 static struct store_db_fields *fields = NULL;
100 
101 static int hash = 0;
102 
103 
104 /*
105  * Convert a Msg structure to a Dict hash.
106  * This will assume we handle the msg->sms type only.
107  */
108 /*
109 static Dict *hash_msg_pack(Msg *msg)
110 {
111  Dict *h;
112 
113  gw_assert(msg->type == sms);
114 
115  h = dict_create(32, octstr_destroy_item);
116 
117 #define INTEGER(name) dict_put(h, octstr_imm(#name), octstr_format("%ld", p->name));
118 #define OCTSTR(name) dict_put(h, octstr_imm(#name), octstr_duplicate(p->name));
119 #define UUID(name) { \
120  char id[UUID_STR_LEN + 1]; \
121  uuid_unparse(p->name, id); \
122  dict_put(h, octstr_imm(#name), octstr_create(id)); \
123  }
124 #define VOID(name)
125 #define MSG(type, stmt) \
126  case type: { struct type *p = &msg->type; stmt } break;
127 
128  switch (msg->type) {
129 #include "msg-decl.h"
130  default:
131  panic(0, "Internal error: unknown message type: %d",
132  msg->type);
133  }
134 
135  return h;
136 }
137 */
138 
139 
140 static Msg *hash_msg_unpack(Dict *hash)
141 {
142  Msg *msg;
143  Octstr *os;
144 
145  if (hash == NULL)
146  return NULL;
147 
148  msg = msg_create(sms);
149 #define INTEGER(name) \
150  if ((os = dict_get(hash, octstr_imm(#name))) != NULL) \
151  p->name = atol(octstr_get_cstr(os));
152 #define OCTSTR(name) p->name = octstr_duplicate(dict_get(hash, octstr_imm(#name)));
153 #define UUID(name) \
154  if ((os = dict_get(hash, octstr_imm(#name))) != NULL) \
155  uuid_parse(octstr_get_cstr(os), p->name);
156 #define VOID(name)
157 #define MSG(type, stmt) \
158  case type: { struct type *p = &msg->type; stmt } break;
159 
160  switch (msg->type) {
161 #include "msg-decl.h"
162  default:
163  panic(0, "Internal error: unknown message type: %d",
164  msg->type);
165  }
166 
167  return msg;
168 }
169 
170 
171 static int store_redis_dump()
172 {
173  /* nothing to do */
174  return 0;
175 }
176 
177 
178 static long store_redis_messages()
179 {
180  return counter ? counter_value(counter) : -1;
181 }
182 
183 
184 static void redis_update(const Octstr *cmd, List *binds)
185 {
186  int res;
187  DBPoolConn *pc;
188 
189 #if defined(REDIS_TRACE)
190  debug("store.redis", 0, "redis cmd: %s", octstr_get_cstr(cmd));
191 #endif
192 
193  pc = dbpool_conn_consume(pool);
194  if (pc == NULL) {
195  error(0, "Database pool got no connection! Redis update failed!");
196  return;
197  }
198 
199  res = dbpool_conn_update(pc, cmd, binds);
200 
201  if (res < 0) {
202  error(0, "Store-Redis: Error while updating: command was `%s'",
203  octstr_get_cstr(cmd));
204  }
205 
207 }
208 
209 
210 static void store_redis_add(Octstr *id, Octstr *os)
211 {
212  Octstr *cmd;
213 
215  cmd = octstr_format("HSET %s %s %s",
216  octstr_get_cstr(fields->table),
218  redis_update(cmd, NULL);
219 
220  octstr_destroy(cmd);
221 }
222 
223 
224 /*
225 static void store_redis_add_hash(Octstr *id, Dict *hash)
226 {
227  List *l, *b;
228  Octstr *cmd, *key, *val;
229 
230  cmd = octstr_create("");
231  b = gwlist_create();
232  gwlist_produce(b, octstr_create("HMSET"));
233  gwlist_produce(b, octstr_duplicate(id));
234  l = dict_keys(hash);
235  while ((key = gwlist_extract_first(l)) != NULL) {
236  if ((val = dict_get(hash, key)) != NULL) {
237  gwlist_produce(b, key);
238  gwlist_produce(b, octstr_duplicate(val));
239  }
240  }
241  gwlist_destroy(l, NULL);
242 
243  redis_update(cmd, b);
244 
245  gwlist_destroy(b, octstr_destroy_item);
246  octstr_destroy(cmd);
247 }
248 */
249 
250 
251 /*
252  * In order to a) speed-up the processing of the bind list in the dbpool_redis.c
253  * module and b) safe space in the redis-server memory, we will only store
254  * values that are set.
255  */
256 static void store_redis_add_msg(Octstr *id, Msg *msg)
257 {
258  List *b;
259  Octstr *cmd;
260  char uuid[UUID_STR_LEN + 1];
261 
262  cmd = octstr_create("");
263  b = gwlist_create();
264  gwlist_produce(b, octstr_create("HMSET"));
266 
267 #define INTEGER(name) \
268  if (p->name != MSG_PARAM_UNDEFINED) { \
269  gwlist_produce(b, octstr_imm(#name)); \
270  gwlist_produce(b, octstr_format("%ld", p->name)); \
271  }
272 #define OCTSTR(name) \
273  if (p->name != NULL) { \
274  gwlist_produce(b, octstr_imm(#name)); \
275  gwlist_produce(b, octstr_duplicate(p->name)); \
276  }
277 #define UUID(name) \
278  gwlist_produce(b, octstr_imm(#name)); \
279  uuid_unparse(p->name, uuid); \
280  gwlist_produce(b, octstr_create(uuid));
281 #define VOID(name)
282 #define MSG(type, stmt) \
283  case type: { struct type *p = &msg->type; stmt } break;
284 
285  switch (msg->type) {
286 #include "msg-decl.h"
287  default:
288  panic(0, "Internal error: unknown message type: %d",
289  msg->type);
290  break;
291  }
292 
293  redis_update(cmd, b);
294 
296  octstr_destroy(cmd);
297 }
298 
299 
300 static void store_redis_delete(Octstr *id)
301 {
302  Octstr *cmd;
303 
304  cmd = octstr_format("HDEL %s %s",
305  octstr_get_cstr(fields->table),
306  octstr_get_cstr(id));
307  redis_update(cmd, NULL);
308 
309  octstr_destroy(cmd);
310 }
311 
312 
313 static void store_redis_delete_hash(Octstr *id)
314 {
315  Octstr *cmd;
316 
317  cmd = octstr_format("DEL %s", octstr_get_cstr(id));
318  redis_update(cmd, NULL);
319 
320  octstr_destroy(cmd);
321 }
322 
323 
324 static struct store_db_fields *store_db_fields_create(CfgGroup *grp)
325 {
326  struct store_db_fields *ret;
327 
328  ret = gw_malloc(sizeof(*ret));
329  gw_assert(ret != NULL);
330  memset(ret, 0, sizeof(*ret));
331 
332  if ((ret->table = cfg_get(grp, octstr_imm("table"))) == NULL) {
333  grp_dump(grp);
334  panic(0, "Directive 'table' is not specified in 'group = store-db' context!");
335  }
336 
337  return ret;
338 }
339 
340 
341 static void store_db_fields_destroy(struct store_db_fields *fields)
342 {
343  /* sanity check */
344  if (fields == NULL)
345  return;
346 
347  octstr_destroy(fields->table);
348  octstr_destroy(fields->field_uuid);
349  octstr_destroy(fields->field_message);
350 
351  gw_free(fields);
352 }
353 
354 
355 static int store_redis_getall(int ignore_err, void(*cb)(Octstr*, void*), void *data)
356 {
357  DBPoolConn *pc;
358  Octstr *cmd;
359  Octstr *os, *key;
360  List *result, *row;
361 
362  cmd = octstr_format("HGETALL %s", octstr_get_cstr(fields->table));
363 
364 #if defined(REDIS_TRACE)
365  debug("store.redis", 0, "redis cmd: %s", octstr_get_cstr(cmd));
366 #endif
367 
368  pc = dbpool_conn_consume(pool);
369  if (pc == NULL) {
370  error(0, "Database pool got no connection! Redis HGETALL failed!");
372  return -1;
373  }
374  if (dbpool_conn_select(pc, cmd, NULL, &result) != 0) {
375  error(0, "Failed to fetch messages from redis with cmd `%s'",
376  octstr_get_cstr(cmd));
377  octstr_destroy(cmd);
379  return -1;
380  }
382  octstr_destroy(cmd);
383 
384  if (gwlist_len(result) == 1 && (row = gwlist_extract_first(result)) != NULL) {
385  while (gwlist_len(row) > 0) {
386  key = gwlist_extract_first(row);
387  os = gwlist_extract_first(row);
388  if (key && os) {
389  debug("store.redis", 0, "Found entry for message ID <%s>", octstr_get_cstr(key));
391  if (os == NULL) {
392  error(0, "Could not base64 decode message ID <%s>", octstr_get_cstr(key));
393  } else {
394  cb(os, data);
395  }
396  }
397  octstr_destroy(os);
398  octstr_destroy(key);
399  }
401  } else {
402  debug("store.redis", 0, "No messages loaded from redis store");
403  }
404  gwlist_destroy(result, NULL);
405 
406  return 0;
407 }
408 
409 
410 static int store_redis_getall_hash(int ignore_err, void(*cb)(Dict*, void*), void *data)
411 {
412  DBPoolConn *pc;
413  Octstr *cmd;
414  Octstr *os, *key, *id;
415  List *result, *row, *result_key, *row_key;
416  Dict *hash;
417 
418  cmd = octstr_create("KEYS *");
419 
420 #if defined(REDIS_TRACE)
421  debug("store.redis", 0, "redis cmd: %s", octstr_get_cstr(cmd));
422 #endif
423 
424  pc = dbpool_conn_consume(pool);
425  if (pc == NULL) {
426  error(0, "Database pool got no connection! Redis KEYS failed!");
428  return -1;
429  }
430  if (dbpool_conn_select(pc, cmd, NULL, &result) != 0) {
431  error(0, "Failed to fetch messages from redis with cmd `%s'",
432  octstr_get_cstr(cmd));
433  octstr_destroy(cmd);
435  return -1;
436  }
437  octstr_destroy(cmd);
438 
439  if (gwlist_len(result) == 1 && ((row = gwlist_extract_first(result)) != NULL)) {
440  while ((id = gwlist_extract_first(row)) != NULL) {
441  cmd = octstr_format("HGETALL %s", octstr_get_cstr(id));
442  if (dbpool_conn_select(pc, cmd, NULL, &result_key) != 0) {
443  error(0, "Failed to fetch messages from redis with cmd `%s'",
444  octstr_get_cstr(cmd));
445  octstr_destroy(cmd);
447  octstr_destroy(id);
449  return -1;
450  }
451  octstr_destroy(cmd);
452 
453  if (gwlist_len(result_key) == 1 && ((row_key = gwlist_extract_first(result_key)) != NULL)) {
454  hash = dict_create(32, octstr_destroy_item);
455  while (gwlist_len(row_key) > 0) {
456  key = gwlist_extract_first(row_key);
457  os = gwlist_extract_first(row_key);
458  if (key && os) {
459  dict_put(hash, key, os);
460  }
461  octstr_destroy(key);
462  }
463  cb(hash, data);
464  dict_destroy(hash);
466  }
467  gwlist_destroy(result_key, NULL);
468  }
470  } else {
471  debug("store.redis", 0, "No messages loaded from redis store");
472  }
474  gwlist_destroy(result, NULL);
475 
476  return 0;
477 }
478 
479 
480 struct status {
481  void(*callback_fn)(Msg* msg, void *data);
482  void *data;
483 };
484 
485 
486 static void status_cb(Octstr *msg_s, void *d)
487 {
488  struct status *data = d;
489  Msg *msg;
490 
491  msg = store_msg_unpack(msg_s);
492  if (msg == NULL)
493  return;
494 
495  data->callback_fn(msg, data->data);
496 
497  msg_destroy(msg);
498 }
499 
500 
501 static void store_redis_for_each_message(void(*callback_fn)(Msg* msg, void *data), void *data)
502 {
503  struct status d;
504 
505  if (pool == NULL)
506  return;
507 
509  d.data = data;
510 
511  /* ignore error because files may disappear */
512  store_redis_getall(1, status_cb, &d);
513 }
514 
515 
516 static void dispatch(Octstr *msg_s, void *data)
517 {
518  Msg *msg;
519  void (*receive_msg)(Msg*) = data;
520 
521  if (msg_s == NULL)
522  return;
523 
524  msg = store_msg_unpack(msg_s);
525  if (msg != NULL) {
526  receive_msg(msg);
527  counter_increase(counter);
528  } else {
529  error(0, "Could not unpack message from redis store!");
530  }
531 }
532 
533 
534 static void dispatch_hash(Dict *msg_h, void *data)
535 {
536  Msg *msg;
537  void (*receive_msg)(Msg*) = data;
538 
539  if (msg_h == NULL)
540  return;
541 
542  msg = hash_msg_unpack(msg_h);
543  if (msg != NULL) {
544  receive_msg(msg);
545  counter_increase(counter);
546  } else {
547  error(0, "Could not unpack message hash from redis store!");
548  }
549 }
550 
551 
552 static int store_redis_load(void(*receive_msg)(Msg*))
553 {
554  int rc;
555 
556  /* check if we are active */
557  if (pool == NULL)
558  return 0;
559 
560  /* sanity check */
561  if (receive_msg == NULL)
562  return -1;
563 
564  /*
565  * We will use a Dict as an intermediate data structure to re-construct the
566  * Msg struct itself. This is faster, then using pre-processor magic and
567  * then strcmp() on the msg field names.
568  */
569  rc = hash ? store_redis_getall_hash(0, dispatch_hash, receive_msg) :
570  store_redis_getall(0, dispatch, receive_msg);
571 
572  info(0, "Loaded %ld messages from store.", counter_value(counter));
573 
574  /* allow using of storage */
575  gwlist_remove_producer(loaded);
576 
577  return rc;
578 }
579 
580 
581 static int store_redis_save(Msg *msg)
582 {
583  char id[UUID_STR_LEN + 1];
584  Octstr *id_s;
585 
586  /* always set msg id and timestamp */
587  if (msg_type(msg) == sms && uuid_is_null(msg->sms.id))
588  uuid_generate(msg->sms.id);
589 
590  if (msg_type(msg) == sms && msg->sms.time == MSG_PARAM_UNDEFINED)
591  time(&msg->sms.time);
592 
593  if (pool == NULL)
594  return 0;
595 
596  /* block here if store still not loaded */
597  gwlist_consume(loaded);
598 
599  switch (msg_type(msg)) {
600  case sms:
601  {
602  uuid_unparse(msg->sms.id, id);
603  id_s = octstr_create(id);
604 
605  /* XXX we could use function pointers to avoid iteration checks */
606  if (hash) {
607  store_redis_add_msg(id_s, msg);
608  } else {
609  Octstr *os = store_msg_pack(msg);
610 
611  if (os == NULL) {
612  error(0, "Could not pack message.");
613  return -1;
614  }
615  store_redis_add(id_s, os);
616  octstr_destroy(os);
617  }
618  octstr_destroy(id_s);
619  counter_increase(counter);
620  break;
621  }
622  case ack:
623  {
624  uuid_unparse(msg->ack.id, id);
625  id_s = octstr_create(id);
626  if (hash)
627  store_redis_delete_hash(id_s);
628  else
629  store_redis_delete(id_s);
630  octstr_destroy(id_s);
631  counter_decrease(counter);
632  break;
633  }
634  default:
635  return -1;
636  }
637 
638  return 0;
639 }
640 
641 
642 static int store_redis_save_ack(Msg *msg, ack_status_t status)
643 {
644  int ret;
645  Msg *nack = msg_create(ack);
646 
647  nack->ack.nack = status;
648  uuid_copy(nack->ack.id, msg->sms.id);
649  nack->ack.time = msg->sms.time;
650  ret = store_redis_save(nack);
651  msg_destroy(nack);
652 
653  return ret;
654 }
655 
656 
657 static void store_redis_shutdown()
658 {
659  dbpool_destroy(pool);
660  store_db_fields_destroy(fields);
661 
662  counter_destroy(counter);
663  gwlist_destroy(loaded, NULL);
664 }
665 
666 
667 int store_redis_init(Cfg *cfg)
668 {
669  CfgGroup *grp;
670  List *grplist;
671  Octstr *redis_host, *redis_pass, *redis_id;
672  long redis_port = 0, redis_database = -1, redis_idle_timeout = -1;
673  Octstr *p = NULL;
674  long pool_size;
675  DBConf *db_conf = NULL;
676 
677  /*
678  * Check for all mandatory directives that specify the field names
679  * of the used Redis key
680  */
681  if (!(grp = cfg_get_single_group(cfg, octstr_imm("store-db"))))
682  panic(0, "Store-Redis: group 'store-db' is not specified!");
683 
684  if (!(redis_id = cfg_get(grp, octstr_imm("id"))))
685  panic(0, "Store-Redis: directive 'id' is not specified!");
686 
687  cfg_get_bool(&hash, grp, octstr_imm("hash"));
688 
689  fields = store_db_fields_create(grp);
690  gw_assert(fields != NULL);
691 
692  /* select corresponding functions */
693  store_messages = store_redis_messages;
694  store_save = store_redis_save;
695  store_save_ack = store_redis_save_ack;
696  store_load = store_redis_load;
697  store_dump = store_redis_dump;
698  store_shutdown = store_redis_shutdown;
699  store_for_each_message = store_redis_for_each_message;
700 
701  /*
702  * Now grab the required information from the 'redis-connection' group
703  * with the id we just obtained.
704  *
705  * We have to loop through all available Redis connection definitions
706  * and search for the one we are looking for.
707  */
708  grplist = cfg_get_multi_group(cfg, octstr_imm("redis-connection"));
709  while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) {
710  p = cfg_get(grp, octstr_imm("id"));
711  if (p != NULL && octstr_compare(p, redis_id) == 0) {
712  goto found;
713  }
714  if (p != NULL)
715  octstr_destroy(p);
716  }
717  panic(0, "Connection settings for 'redis-connection' with id '%s' are not specified!",
718  octstr_get_cstr(redis_id));
719 
720 found:
721  octstr_destroy(p);
722  gwlist_destroy(grplist, NULL);
723 
724  if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0)
725  pool_size = 1;
726 
727  if (!(redis_host = cfg_get(grp, octstr_imm("host")))) {
728  grp_dump(grp);
729  panic(0, "Directive 'host' is not specified in 'group = redis-connection' context!");
730  }
731  if (cfg_get_integer(&redis_port, grp, octstr_imm("port")) == -1) {
732  grp_dump(grp);
733  panic(0, "Directive 'port' is not specified in 'group = redis-connection' context!");
734  }
735  redis_pass = cfg_get(grp, octstr_imm("password"));
736  cfg_get_integer(&redis_database, grp, octstr_imm("database"));
737  cfg_get_integer(&redis_idle_timeout, grp, octstr_imm("idle-timeout"));
738 
739  /*
740  * Ok, ready to connect to Redis
741  */
742  db_conf = gw_malloc(sizeof(DBConf));
743  gw_assert(db_conf != NULL);
744 
745  db_conf->redis = gw_malloc(sizeof(RedisConf));
746  gw_assert(db_conf->redis != NULL);
747 
748  db_conf->redis->host = redis_host;
749  db_conf->redis->port = redis_port;
750  db_conf->redis->password = redis_pass;
751  db_conf->redis->database = redis_database;
752  db_conf->redis->idle_timeout = redis_idle_timeout;
753 
754  pool = dbpool_create(DBPOOL_REDIS, db_conf, pool_size);
755  gw_assert(pool != NULL);
756 
757  /*
758  * Panic on failure to connect. Should we just try to reconnect?
759  */
760  if (dbpool_conn_count(pool) == 0)
761  panic(0, "Redis database pool has no connections!");
762 
763  loaded = gwlist_create();
764  gwlist_add_producer(loaded);
765  counter = counter_create();
766 
767  octstr_destroy(redis_id);
768 
769  return 0;
770 }
771 
772 #endif
Dict * dict_create(long size_hint, void(*destroy_value)(void *))
Definition: dict.c:192
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
long dbpool_conn_count(DBPool *p)
DBPool * dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections)
RedisConf * redis
Definition: dbpool.h:172
void dict_put(Dict *dict, Octstr *key, void *value)
Definition: dict.c:240
void counter_destroy(Counter *counter)
Definition: counter.c:110
void gwlist_produce(List *list, void *item)
Definition: list.c:411
long gwlist_len(List *list)
Definition: list.c:166
int(* store_save_ack)(Msg *msg, ack_status_t status)
Definition: bb_store.c:73
static List * loaded
Definition: bb_store_file.c:99
long(* store_messages)(void)
Definition: bb_store.c:71
static void dispatch(const Octstr *filename, void *data)
msg_type
Definition: msg.h:73
#define cfg_get(grp, varname)
Definition: cfg.h:86
void octstr_binary_to_base64(Octstr *ostr)
Definition: octstr.c:540
void uuid_unparse(const uuid_t uu, char *out)
Definition: gw_uuid.c:561
void uuid_generate(uuid_t out)
Definition: gw_uuid.c:392
#define msg_create(type)
Definition: msg.h:136
unsigned long counter_decrease(Counter *counter)
Definition: counter.c:155
Msg *(* store_msg_unpack)(Octstr *os)
Definition: bb_store.c:78
int(* store_dump)(void)
Definition: bb_store.c:75
Octstr * password
Definition: dbpool.h:150
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
unsigned long counter_increase(Counter *counter)
Definition: counter.c:123
static struct pid_list * found
void(* store_for_each_message)(void(*callback_fn)(Msg *msg, void *data), void *data)
Definition: bb_store.c:79
void dbpool_conn_produce(DBPoolConn *conn)
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
Definition: msg.h:79
Definition: cfg.c:164
Counter * counter_create(void)
Definition: counter.c:94
Definition: gw_uuid.c:62
void * gwlist_extract_first(List *list)
Definition: list.c:305
void grp_dump(CfgGroup *grp)
Definition: cfg.c:808
void gwlist_remove_producer(List *list)
Definition: list.c:401
int uuid_is_null(const uuid_t uu)
Definition: gw_uuid.c:412
Definition: dict.c:116
#define octstr_duplicate(ostr)
Definition: octstr.h:187
List * cfg_get_multi_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:642
void uuid_copy(uuid_t dst, const uuid_t src)
Definition: gw_uuid.c:150
void msg_destroy(Msg *msg)
Definition: msg.c:132
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
unsigned long counter_value(Counter *counter)
Definition: counter.c:145
gw_assert(wtls_machine->packet_to_send!=NULL)
void * data
Octstr *(* store_msg_pack)(Msg *msg)
Definition: bb_store.c:77
void octstr_base64_to_binary(Octstr *ostr)
Definition: octstr.c:661
#define UUID_STR_LEN
Definition: gw_uuid.h:19
long database
Definition: dbpool.h:151
void(* store_shutdown)(void)
Definition: bb_store.c:76
Definition: dbpool.h:164
static Cfg * cfg
Definition: smsbox.c:115
void dict_destroy(Dict *dict)
Definition: dict.c:215
void dbpool_destroy(DBPool *p)
int dbpool_conn_update(DBPoolConn *conn, const Octstr *sql, List *binds)
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:756
Definition: octstr.c:118
void * gwlist_consume(List *list)
Definition: list.c:427
long port
Definition: dbpool.h:149
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:739
#define panic
Definition: log.h:87
Definition: cfg.c:73
int(* store_load)(void(*receive_msg)(Msg *))
Definition: bb_store.c:74
#define MSG_PARAM_UNDEFINED
Definition: msg.h:71
static void status_cb(Msg *msg, void *d)
Definition: bb_store.c:111
int dbpool_conn_select(DBPoolConn *conn, const Octstr *sql, List *binds, List **result)
#define gwlist_create()
Definition: list.h:136
void(* callback_fn)(Msg *msg, void *data)
enum msg_type type
Definition: msg.h:80
int(* store_save)(Msg *msg)
Definition: bb_store.c:72
DBPoolConn * dbpool_conn_consume(DBPool *p)
ack_status_t
Definition: msg.h:124
Octstr * host
Definition: dbpool.h:148
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:636
void gwlist_add_producer(List *list)
Definition: list.c:383
Definition: list.c:102
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static Counter * counter
Octstr * status
Definition: bb_store.c:108
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
long idle_timeout
Definition: dbpool.h:152
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.