Kannel: Open Source WAP and SMS gateway  svn-r5335
sqlbox_pgsql.c
Go to the documentation of this file.
1 #include "gwlib/gwlib.h"
2 #ifdef HAVE_PGSQL
3 #include "gwlib/dbpool.h"
4 #include "sqlbox_pgsql.h"
5 #include <libpq-fe.h>
6 
7 #define sql_update pgsql_update
8 #define sql_select pgsql_select
9 #define exit_nicely(conn) do { PQfinish(conn); } while(0)
10 
11 static Octstr *sqlbox_logtable;
12 static Octstr *sqlbox_insert_table;
13 
14 /*
15  * Our connection pool to pgsql.
16  */
17 
18 static DBPool *pool = NULL;
19 
20 /*
21  *-------------------------------------------------
22  * Postgres SQL thingies
23  *-------------------------------------------------
24 */
25 
26 static void pgsql_update(const Octstr *sql)
27 {
28  DBPoolConn *pc;
29  PGresult *res;
30  ExecStatusType status;
31 
32 #if defined(SQLBOX_TRACE)
33  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql));
34 #endif
35 
36  pc = dbpool_conn_consume(pool);
37  if (pc == NULL) {
38  error(0, "PGSQL: Database pool got no connection! DB update failed!");
39  return;
40  }
41 
42  res = PQexec(pc->conn, octstr_get_cstr(sql));
43  status = PQresultStatus(res);
44  switch(status) {
45  case PGRES_BAD_RESPONSE:
46  case PGRES_NONFATAL_ERROR:
47  case PGRES_FATAL_ERROR:
48  error (0, "PGSQL: %s", PQresultErrorMessage(res));
49  break;
50  default:
51  /* Don't handle the other PGRES_foobar enumerates. */
52  break;
53  }
54 
56 }
57 
58 static PGresult *pgsql_select(const Octstr *sql)
59 {
60  PGresult *res = NULL;
61  DBPoolConn *pc;
62 
63 #if defined(SQLBOX_TRACE)
64  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql));
65 #endif
66 
67  pc = dbpool_conn_consume(pool);
68  if (pc == NULL) {
69  error(0, "PGSQL: Database pool got no connection! DB operation failed!");
70  return NULL;
71  }
72 
73  res = PQexec(pc->conn, octstr_get_cstr(sql));
74  switch (PQresultStatus(res)) {
75  case PGRES_EMPTY_QUERY:
76  case PGRES_BAD_RESPONSE:
77  case PGRES_NONFATAL_ERROR:
78  case PGRES_FATAL_ERROR:
79  error(0, "PGSQL: %s", PQresultErrorMessage(res));
80  break;
81  default:
82  /* all other enum values are not handled. */
83  break;
84  }
86  return res;
87 }
88 
89 void sqlbox_configure_pgsql(Cfg* cfg)
90 {
91  CfgGroup *grp;
92  Octstr *sql;
93 
94  if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox"))))
95  panic(0, "SQLBOX: PGSQL: group 'sqlbox' is not specified!");
96 
97  sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table"));
98  if (sqlbox_logtable == NULL) {
99  panic(0, "No 'sql-log-table' not configured.");
100  }
101  sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table"));
102  if (sqlbox_insert_table == NULL) {
103  panic(0, "No 'sql-insert-table' not configured.");
104  }
105 
106  /* create send_sms && sent_sms tables if they do not exist */
107  sql = octstr_format(SQLBOX_PGSQL_CREATE_LOG_TABLE, sqlbox_logtable);
108  sql_update(sql);
109  octstr_destroy(sql);
110  sql = octstr_format(SQLBOX_PGSQL_CREATE_INSERT_TABLE, sqlbox_insert_table);
111  sql_update(sql);
112  octstr_destroy(sql);
113  /* end table creation */
114 }
115 
116 static Octstr *get_numeric_value_or_return_null(long int num)
117 {
118  if (num == -1) {
119  return octstr_create("NULL");
120  }
121  return octstr_format("%ld", num);
122 }
123 
124 static Octstr *get_string_value_or_return_null(Octstr *str)
125 {
126  if (str == NULL) {
127  return octstr_create("NULL");
128  }
129  if (octstr_compare(str, octstr_imm("")) == 0) {
130  return octstr_create("NULL");
131  }
132  octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\"));
133  octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'"));
134  return octstr_format("\'%S\'", str);
135 }
136 
137 #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x))
138 #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x))
139 
140 void pgsql_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */)
141 {
142  Octstr *sql;
143  Octstr *stuffer[30];
144  int stuffcount = 0;
145 
146  sql = octstr_format(SQLBOX_PGSQL_INSERT_QUERY, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender),
147  st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time),
148  st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type),
149  st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress),
150  st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url),
151  st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset),
152  st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data), st_str(msg->sms.foreign_id));
153  sql_update(sql);
154  //debug("sqlbox", 0, "sql_save_msg: %s", octstr_get_cstr(sql));
155  while (stuffcount > 0) {
156  octstr_destroy(stuffer[--stuffcount]);
157  }
158  octstr_destroy(sql);
159 }
160 
161 void pgsql_leave()
162 {
163  dbpool_destroy(pool);
164 }
165 
166 #define octstr_null_create(x) (octstr_create(PQgetvalue(res, 0, x)))
167 #define atol_null(x) ((PQgetisnull(res, 0, x) == 0) ? atol(PQgetvalue(res, 0, x)) : -1)
168 Msg *pgsql_fetch_msg()
169 {
170  Msg *msg = NULL;
171  Octstr *sql, *delet, *id;
172  PGresult *res;
173 
174  sql = octstr_format(SQLBOX_PGSQL_SELECT_QUERY, sqlbox_insert_table);
175 #if defined(SQLBOX_TRACE)
176  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql));
177 #endif
178  res = pgsql_select(sql);
179  if (res == NULL) {
180  debug("sqlbox", 0, "SQL statement failed: %s", octstr_get_cstr(sql));
181  }
182  else {
183  if (PQntuples(res) >= 1) {
184  id = octstr_null_create(0);
185  /* save fields in this row as msg struct */
186  msg = msg_create(sms);
187  /* we abuse the foreign_id field in the message struct for our sql_id value */
188  msg->sms.foreign_id = octstr_null_create(0);
189  msg->sms.sender = octstr_null_create(2);
190  msg->sms.receiver = octstr_null_create(3);
191  msg->sms.udhdata = octstr_null_create(4);
192  msg->sms.msgdata = octstr_null_create(5);
193  msg->sms.time = atol_null(6);
194  msg->sms.smsc_id = octstr_null_create(7);
195  msg->sms.service = octstr_null_create(8);
196  msg->sms.account = octstr_null_create(9);
197  /* msg->sms.id = atol_null(row[10]); */
198  msg->sms.sms_type = atol_null(11);
199  msg->sms.mclass = atol_null(12);
200  msg->sms.mwi = atol_null(13);
201  msg->sms.coding = atol_null(14);
202  msg->sms.compress = atol_null(15);
203  msg->sms.validity = atol_null(16);
204  msg->sms.deferred = atol_null(17);
205  msg->sms.dlr_mask = atol_null(18);
206  msg->sms.dlr_url = octstr_null_create(19);
207  msg->sms.pid = atol_null(20);
208  msg->sms.alt_dcs = atol_null(21);
209  msg->sms.rpi = atol_null(22);
210  msg->sms.charset = octstr_null_create(23);
211  msg->sms.binfo = octstr_null_create(25);
212  msg->sms.meta_data = octstr_null_create(26);
213  if ((PQgetvalue(res, 0, 24)) == NULL) {
214  msg->sms.boxc_id= octstr_duplicate(sqlbox_id);
215  }
216  else {
217  msg->sms.boxc_id= octstr_null_create(24);
218  }
219  /* delete current row */
220  delet = octstr_format(SQLBOX_PGSQL_DELETE_QUERY, sqlbox_insert_table, id);
221 #if defined(SQLBOX_TRACE)
222  debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet));
223 #endif
224  pgsql_update(delet);
225  octstr_destroy(id);
226  octstr_destroy(delet);
227  }
228  PQclear(res);
229  }
230  octstr_destroy(sql);
231  //debug("sqlbox", 0, "sql_fetch_msg: %s", octstr_get_cstr(sql));
232  return msg;
233 }
234 
235 struct server_type *sqlbox_init_pgsql(Cfg* cfg)
236 {
237  CfgGroup *grp;
238  List *grplist;
239  Octstr *pgsql_host, *pgsql_user, *pgsql_pass, *pgsql_db, *pgsql_id;
240  Octstr *p = NULL;
241  long pool_size, pgsql_port;
242  int have_port;
243  DBConf *db_conf = NULL;
244  struct server_type *res = NULL;
245 
246  /*
247  * check for all mandatory directives that specify the field names
248  * of the used PGSQL table
249  */
250  if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox"))))
251  panic(0, "SQLBOX: PGSQL: group 'sqlbox' is not specified!");
252 
253  if (!(pgsql_id = cfg_get(grp, octstr_imm("id"))))
254  panic(0, "SQLBOX: PGSQL: directive 'id' is not specified!");
255 
256  /*
257  * now grap the required information from the 'pgsql-connection' group
258  * with the pgsql-id we just obtained
259  *
260  * we have to loop through all available PGSQL connection definitions
261  * and search for the one we are looking for
262  */
263 
264  grplist = cfg_get_multi_group(cfg, octstr_imm("pgsql-connection"));
265  while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) {
266  p = cfg_get(grp, octstr_imm("id"));
267  if (p != NULL && octstr_compare(p, pgsql_id) == 0) {
268  goto found;
269  }
270  if (p != NULL) octstr_destroy(p);
271  }
272  panic(0, "SQLBOX: PGSQL: connection settings for id '%s' are not specified!",
273  octstr_get_cstr(pgsql_id));
274 
275 found:
276  octstr_destroy(p);
277  gwlist_destroy(grplist, NULL);
278 
279  if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0)
280  pool_size = 1;
281 
282  if (!(pgsql_host = cfg_get(grp, octstr_imm("host"))))
283  panic(0, "SQLBOX: PGSQL: directive 'host' is not specified!");
284  if (!(pgsql_user = cfg_get(grp, octstr_imm("username"))))
285  panic(0, "SQLBOX: PGSQL: directive 'username' is not specified!");
286  if (!(pgsql_pass = cfg_get(grp, octstr_imm("password"))))
287  panic(0, "SQLBOX: PGSQL: directive 'password' is not specified!");
288  if (!(pgsql_db = cfg_get(grp, octstr_imm("database"))))
289  panic(0, "SQLBOX: PGSQL: directive 'database' is not specified!");
290  have_port = (cfg_get_integer(&pgsql_port, grp, octstr_imm("port")) != -1);
291 
292  /*
293  * ok, ready to connect to PGSQL
294  */
295  db_conf = gw_malloc(sizeof(DBConf));
296  gw_assert(db_conf != NULL);
297 
298  db_conf->pgsql = gw_malloc(sizeof(PgSQLConf));
299  gw_assert(db_conf->pgsql != NULL);
300 
301  db_conf->pgsql->host = pgsql_host;
302  db_conf->pgsql->username = pgsql_user;
303  db_conf->pgsql->password = pgsql_pass;
304  db_conf->pgsql->database = pgsql_db;
305  if (have_port) {
306  db_conf->pgsql->port = pgsql_port;
307  }
308 
309  pool = dbpool_create(DBPOOL_PGSQL, db_conf, pool_size);
310  gw_assert(pool != NULL);
311 
312  /*
313  * XXX should a failing connect throw panic?!
314  */
315  if (dbpool_conn_count(pool) == 0)
316  panic(0,"SQLBOX: PGSQL: database pool has no connections!");
317 
318  octstr_destroy(pgsql_id);
319 
320  res = gw_malloc(sizeof(struct server_type));
321  gw_assert(res != NULL);
322 
323  res->type = octstr_create("PGSQL");
324  res->sql_enter = sqlbox_configure_pgsql;
325  res->sql_leave = pgsql_leave;
326  res->sql_fetch_msg = pgsql_fetch_msg;
327  res->sql_save_msg = pgsql_save_msg;
328  res->sql_fetch_msg_list = NULL;
329  res->sql_save_list = NULL;
330  return res;
331 }
332 
333 #endif
void error(int err, const char *fmt,...)
Definition: log.c:648
int(* sql_fetch_msg_list)(List *, long)
Definition: sqlbox_sql.h:19
void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl)
Definition: octstr.c:2649
long dbpool_conn_count(DBPool *p)
DBPool * dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections)
gw_assert(wtls_machine->packet_to_send !=NULL)
#define cfg_get(grp, varname)
Definition: cfg.h:86
#define msg_create(type)
Definition: msg.h:136
Octstr * username
Definition: dbpool.h:140
void(* sql_save_list)(List *, Octstr *, int)
Definition: sqlbox_sql.h:20
static Cfg * cfg
Definition: opensmppbox.c:95
void(* sql_leave)()
Definition: sqlbox_sql.h:16
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static struct pid_list * found
void(* sql_enter)(Cfg *)
Definition: sqlbox_sql.h:15
void dbpool_conn_produce(DBPoolConn *conn)
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
Definition: msg.h:79
Definition: cfg.c:164
PgSQLConf * pgsql
Definition: dbpool.h:171
void * gwlist_extract_first(List *list)
Definition: list.c:305
Msg *(* sql_fetch_msg)()
Definition: sqlbox_sql.h:17
#define octstr_duplicate(ostr)
Definition: octstr.h:187
List * cfg_get_multi_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:645
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
Octstr * password
Definition: dbpool.h:141
Definition: dbpool.h:164
void dbpool_destroy(DBPool *p)
Octstr * database
Definition: dbpool.h:142
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
#define panic
Definition: log.h:87
Definition: cfg.c:73
long port
Definition: dbpool.h:139
DBPoolConn * dbpool_conn_consume(DBPool *p)
Octstr * type
Definition: sqlbox_sql.h:14
void * conn
Definition: dbpool.h:95
CfgGroup * cfg_get_single_group(Cfg *cfg, Octstr *name)
Definition: cfg.c:639
Octstr * sqlbox_id
Definition: sqlbox.c:95
Octstr * host
Definition: dbpool.h:138
Definition: list.c:102
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
void(* sql_save_msg)(Msg *, Octstr *)
Definition: sqlbox_sql.h:18
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871
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.