static void dlr_add_mssql(struct dlr_entry *entry) { Octstr *sql; DBPoolConn *pconn; debug("dlr.mssql", 0, "adding DLR entry into database"); int res; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { dlr_entry_destroy(entry); return; } sql = octstr_format("INSERT INTO %S (%S, %S, %S, %S, %S, %S, %S, %S, %S) VALUES " "('%S', '%S', '%S', '%S', '%S', '%S', '%d', '%S', '%d')", fields->table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status, entry->smsc, entry->timestamp, entry->source, entry->destination, entry->service, entry->url, entry->mask, entry->boxc_id, 0); #if defined(DLR_TRACE) debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, NULL)) == -1) error(0, "DLR: MSSQL: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); else if (!res) warning(0, "DLR: MSSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); dlr_entry_destroy(entry); }
static void dlr_sdb_add(struct dlr_entry *dlr) { Octstr *sql; int state; sql = octstr_format("INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES " "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d')", octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc), octstr_get_cstr(fields->field_status), octstr_get_cstr(dlr->smsc), octstr_get_cstr(dlr->timestamp), octstr_get_cstr(dlr->source), octstr_get_cstr(dlr->destination), octstr_get_cstr(dlr->service), octstr_get_cstr(dlr->url), dlr->mask, octstr_get_cstr(dlr->boxc_id), 0); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL); if (state == -1) error(0, "SDB: error in inserting DLR for DST <%s>", octstr_get_cstr(dlr->destination)); else if (!state) warning(0, "SDB: No dlr inserted for DST <%s>", octstr_get_cstr(dlr->destination)); octstr_destroy(sql); dlr_entry_destroy(dlr); }
static void dlr_mysql_add(struct dlr_entry *entry) { Octstr *sql, *os_mask; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.mysql", 0, "adding DLR entry into database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { dlr_entry_destroy(entry); return; } sql = octstr_format("INSERT INTO `%S` (`%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`) VALUES " "(?, ?, ?, ?, ?, ?, ?, ?, 0)", fields->table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status); os_mask = octstr_format("%d", entry->mask); gwlist_append(binds, entry->smsc); gwlist_append(binds, entry->timestamp); gwlist_append(binds, entry->source); gwlist_append(binds, entry->destination); gwlist_append(binds, entry->service); gwlist_append(binds, entry->url); gwlist_append(binds, os_mask); gwlist_append(binds, entry->boxc_id); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: MYSQL: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); else if (!res) warning(0, "DLR: MYSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); gwlist_destroy(binds, NULL); octstr_destroy(os_mask); dlr_entry_destroy(entry); }
/* Add a new DLR entry to MongoDB */ static void dlr_mongodb_add(struct dlr_entry *entry) { DBPoolConn *pconn; bson b; bson_buffer buf; mongo_connection *conn = NULL; pconn = dbpool_conn_consume(pool); if (pconn == NULL) { dlr_entry_destroy(entry); return; } conn = (mongo_connection*)pconn->conn; bson_buffer_init(&buf); bson_append_new_oid(&buf, "_id"); bson_append_string(&buf, octstr_get_cstr(fields->field_smsc), octstr_get_cstr(entry->smsc)); bson_append_string(&buf, octstr_get_cstr(fields->field_ts), octstr_get_cstr(entry->timestamp)); bson_append_string(&buf, octstr_get_cstr(fields->field_src), octstr_get_cstr(entry->source)); bson_append_string(&buf, octstr_get_cstr(fields->field_dst), octstr_get_cstr(entry->destination)); bson_append_string(&buf, octstr_get_cstr(fields->field_serv), octstr_get_cstr(entry->service)); bson_append_string(&buf, octstr_get_cstr(fields->field_url), octstr_get_cstr(entry->url)); bson_append_string(&buf, octstr_get_cstr(fields->field_account), octstr_get_cstr(entry->account)); bson_append_string(&buf, octstr_get_cstr(fields->field_binfo), octstr_get_cstr(entry->binfo)); bson_append_int(&buf, octstr_get_cstr(fields->field_mask), entry->mask); bson_append_string(&buf, octstr_get_cstr(fields->field_boxc), octstr_get_cstr(entry->boxc_id)); bson_append_int(&buf, octstr_get_cstr(fields->field_status), 0); bson_from_buffer(&b, &buf); /* TODO: namespace support */ MONGO_TRY { mongo_insert(conn, mongodb_namespace, &b); } MONGO_CATCH { mongodb_error("dlr_mongodb_insert", conn->exception.type); } dbpool_conn_produce(pconn); bson_destroy(&b); dlr_entry_destroy(entry); }
static void dlr_add_oracle(struct dlr_entry *entry) { Octstr *sql, *os_mask; DBPoolConn *pconn; List *binds = gwlist_create(); debug("dlr.oracle", 0, "adding DLR entry into database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { dlr_entry_destroy(entry); return; } sql = octstr_format("INSERT INTO %S (%S, %S, %S, %S, %S, %S, %S, %S, %S) VALUES " "(:1, :2, :3, :4, :5, :6, :7, :8, 0)", fields->table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status); os_mask = octstr_format("%d", entry->mask); gwlist_append(binds, entry->smsc); /* :1 */ gwlist_append(binds, entry->timestamp); /* :2 */ gwlist_append(binds, entry->source); /* :3 */ gwlist_append(binds, entry->destination); /* :4 */ gwlist_append(binds, entry->service); /* :5 */ gwlist_append(binds, entry->url); /* :6 */ gwlist_append(binds, os_mask); /* :7 */ gwlist_append(binds, entry->boxc_id); /* :8 */ #if defined(DLR_TRACE) debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_update(pconn, sql, binds) == -1) error(0, "DLR: ORACLE: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); gwlist_destroy(binds, NULL); octstr_destroy(os_mask); dlr_entry_destroy(entry); }
static struct dlr_entry* dlr_sdb_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; int state; struct dlr_entry *res = dlr_entry_create(); gw_assert(res != NULL); if (dst) like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("SELECT %S, %S, %S, %S, %S, %S FROM %S WHERE %S='%S' " "AND %S='%S' %S %s", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like, sdb_get_limit_str()); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_add, res); octstr_destroy(sql); octstr_destroy(like); if (state == -1) { error(0, "SDB: error in finding DLR"); goto notfound; } else if (state == 0) { debug("dlr.sdb", 0, "SDB: no entry found for DST <%s>.", octstr_get_cstr(dst)); goto notfound; } res->smsc = octstr_duplicate(smsc); return res; notfound: dlr_entry_destroy(res); return NULL; }
static void dlr_pgsql_add(struct dlr_entry *entry) { Octstr *sql; sql = octstr_format("INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES " "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d');", octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc), octstr_get_cstr(fields->field_status), octstr_get_cstr(entry->smsc), octstr_get_cstr(entry->timestamp), octstr_get_cstr(entry->source), octstr_get_cstr(entry->destination), octstr_get_cstr(entry->service), octstr_get_cstr(entry->url), entry->mask, octstr_get_cstr(entry->boxc_id), 0); pgsql_update(sql); octstr_destroy(sql); dlr_entry_destroy(entry); }
static struct dlr_entry* dlr_sdb_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql; int state; struct dlr_entry *res = dlr_entry_create(); gw_assert(res != NULL); sql = octstr_format("SELECT %s, %s, %s, %s, %s, %s FROM %s WHERE %s='%s' AND %s='%s' %s", octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_boxc), octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts), sdb_get_limit_str()); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_add, res); octstr_destroy(sql); if (state == -1) { error(0, "SDB: error in finding DLR"); goto notfound; } else if (state == 0) { debug("dlr.sdb", 0, "SDB: no entry found for DST <%s>.", octstr_get_cstr(dst)); goto notfound; } res->smsc = octstr_duplicate(smsc); return res; notfound: dlr_entry_destroy(res); return NULL; }
static void dlr_pgsql_add(struct dlr_entry *entry) { Octstr *sql; sql = octstr_format("INSERT INTO \"%s\" (\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\") VALUES " "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d');", octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc), octstr_get_cstr(fields->field_status), octstr_get_cstr(entry->smsc), octstr_get_cstr(entry->timestamp), octstr_get_cstr(entry->source), octstr_get_cstr(entry->destination), octstr_get_cstr(entry->service), octstr_get_cstr(entry->url), entry->mask, octstr_get_cstr(entry->boxc_id), 0); if (!pgsql_update(sql)) warning(0, "DLR: PGSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); octstr_destroy(sql); dlr_entry_destroy(entry); }
/* * Return Msg* if dlr entry found in DB, otherwise NULL. * NOTE: If typ is end status (e.g. DELIVERED) then dlr entry * will be removed from DB. */ Msg *dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ) { Msg *msg = NULL; struct dlr_entry *dlr = NULL; if(octstr_len(smsc) == 0) { warning(0, "DLR[%s]: Can't find a dlr without smsc-id", dlr_type()); return NULL; } /* check if we have handler registered */ if (handles == NULL || handles->dlr_get == NULL) return NULL; debug("dlr.dlr", 0, "DLR[%s]: Looking for DLR smsc=%s, ts=%s, dst=%s, type=%d", dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(ts), octstr_get_cstr(dst), typ); dlr = handles->dlr_get(smsc, ts, dst); if (dlr == NULL) { warning(0, "DLR[%s]: DLR from SMSC<%s> for DST<%s> not found.", dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(dst)); return NULL; } #define O_SET(x, val) if (octstr_len(val) > 0) { x = val; val = NULL; } if ((typ & dlr->mask) > 0) { /* its an entry we are interested in */ msg = msg_create(sms); msg->sms.sms_type = report_mo; msg->sms.dlr_mask = typ; O_SET(msg->sms.service, dlr->service); O_SET(msg->sms.smsc_id, dlr->smsc); O_SET(msg->sms.receiver, dlr->destination); O_SET(msg->sms.sender, dlr->source); /* if dlr_url was present, recode it here again */ O_SET(msg->sms.dlr_url, dlr->url); /* add the foreign_id */ msg->sms.foreign_id = octstr_duplicate(ts); /* * insert original message to the data segment * later in the smsc module */ msg->sms.msgdata = NULL; /* * If a boxc_id is available, then instruct bearerbox to * route this msg back to originating smsbox */ O_SET(msg->sms.boxc_id, dlr->boxc_id); time(&msg->sms.time); debug("dlr.dlr", 0, "DLR[%s]: created DLR message for URL <%s>", dlr_type(), (msg->sms.dlr_url?octstr_get_cstr(msg->sms.dlr_url):"")); } else { debug("dlr.dlr", 0, "DLR[%s]: Ignoring DLR message because of mask type=%d dlr->mask=%d", dlr_type(), typ, dlr->mask); /* ok that was a status report but we where not interested in having it */ msg = NULL; } #undef O_SET /* check for end status and if so remove from storage */ if ((typ & DLR_BUFFERED) && ((dlr->mask & DLR_SUCCESS) || (dlr->mask & DLR_FAIL))) { debug("dlr.dlr", 0, "DLR[%s]: DLR not destroyed, still waiting for other delivery report", dlr_type()); /* update dlr entry status if function defined */ if (handles != NULL && handles->dlr_update != NULL) handles->dlr_update(smsc, ts, dst, typ); } else { if (handles != NULL && handles->dlr_remove != NULL) { /* it's not good for internal storage, but better for all others */ handles->dlr_remove(smsc, ts, dst); } else { warning(0, "DLR[%s]: Storage don't have remove operation defined", dlr_type()); } } /* destroy struct dlr_entry */ dlr_entry_destroy(dlr); return msg; }
static void dlr_redis_add(struct dlr_entry *entry) { Octstr *key, *sql, *os_mask; Octstr *dstclean, *srcclean, *tsclean; DBPoolConn *pconn; List *binds; int res, len; debug("dlr.redis", 0, "Adding DLR into keystore"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { error(0, "DLR: REDIS: No connection available - dropping DLR"); dlr_entry_destroy(entry); return; } /* * This code is needed as we are mis-using the Hiredis API and * passing a fully-formed Redis command rather than tokenized * command components. Redis treats a space are a command delimiter * so any component that can include a space needs to be quoted. * Should be re-written to use the RedisCommandArgv() API. */ dstclean = octstr_duplicate(entry->destination); octstr_replace(dstclean, octstr_imm(" "), octstr_imm("__space__")); srcclean = octstr_duplicate(entry->source); octstr_replace(srcclean, octstr_imm(" "), octstr_imm("__space__")); tsclean = octstr_duplicate(entry->timestamp); octstr_replace(tsclean, octstr_imm(" "), octstr_imm("__space__")); if (entry->use_dst && entry->destination) { Octstr *dst_min; /* keep a shorten version for the key part */ dst_min = octstr_duplicate(dstclean); len = octstr_len(dst_min); if (len > MIN_DST_LEN) octstr_delete(dst_min, 0, len - MIN_DST_LEN); key = octstr_format("%S:%S:%S:%S", fields->table, entry->smsc, tsclean, dst_min); octstr_destroy(dst_min); } else { key = octstr_format("%S:%S:%S", fields->table, entry->smsc, tsclean); } #ifdef REDIS_PRECHECK binds = gwlist_create(); sql = octstr_format("HSETNX %S %S ?", key, fields->field_smsc); if (dbpool_conn_update(pconn, sql, binds) != 1) { error(0, "DLR: REDIS: DLR for %s already exists! Duplicate Message ID?", octstr_get_cstr(key)); octstr_destroy(sql); octstr_destroy(key); octstr_destroy(tsclean); octstr_destroy(dstclean); octstr_destroy(srcclean); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return; } octstr_destroy(sql); gwlist_destroy(binds, NULL); #endif binds = gwlist_create(); sql = octstr_format("HMSET %S %S ? %S ? %S ? %S ? %S ? %S ? %S ? %S ? %S 0", key, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status); /* prepare values */ if (entry->url) { octstr_url_encode(entry->url); octstr_replace(entry->url, octstr_imm("%"), octstr_imm("%%")); } os_mask = octstr_format("%d", entry->mask); gwlist_append(binds, entry->smsc); gwlist_append(binds, tsclean); gwlist_append(binds, srcclean); gwlist_append(binds, dstclean); gwlist_append(binds, entry->service); gwlist_append(binds, entry->url); gwlist_append(binds, os_mask); gwlist_append(binds, entry->boxc_id); res = dbpool_conn_update(pconn, sql, binds); if (res == -1) { error(0, "DLR: REDIS: Error while adding dlr entry %s:%s:%s:%s", octstr_get_cstr(fields->table), octstr_get_cstr(entry->smsc), octstr_get_cstr(tsclean), octstr_get_cstr(dstclean)); } else { /* HMSET returned OK. Set EXPIRE if applicable and then * increment the DLR counter */ if (fields->ttl) { octstr_destroy(sql); sql = octstr_format("EXPIRE %S %ld", key, fields->ttl); res = dbpool_conn_update(pconn, sql, NULL); } /* We are not performing an 'INCR <table>:Count' * operation here, since we can't be accurate due * to TTL'ed expiration. Rather use 'DBSIZE' based * on seperated databases in redis. */ } dbpool_conn_produce(pconn); octstr_destroy(os_mask); octstr_destroy(sql); octstr_destroy(key); octstr_destroy(tsclean); octstr_destroy(dstclean); octstr_destroy(srcclean); gwlist_destroy(binds, NULL); dlr_entry_destroy(entry); }
/* * Adds a struct dlr_entry to the spool directory. */ static void dlr_spool_add(struct dlr_entry *dlr) { Msg *msg; Octstr *os, *hash, *dir, *filename; int fd; size_t wrc; #define MAP(to, from) \ to = from; \ from = NULL; /* create a common message structure to contain our values */ msg = msg_create(sms); msg->sms.sms_type = report_mt; MAP(msg->sms.smsc_id, dlr->smsc); MAP(msg->sms.foreign_id, dlr->timestamp); MAP(msg->sms.sender, dlr->source); MAP(msg->sms.receiver, dlr->destination); MAP(msg->sms.service, dlr->service); MAP(msg->sms.dlr_url, dlr->url); MAP(msg->sms.boxc_id, dlr->boxc_id); msg->sms.dlr_mask = dlr->mask; /* we got all values, destroy the structure now */ dlr_entry_destroy(dlr); /* create hash value */ os = octstr_duplicate(msg->sms.smsc_id); octstr_append(os, msg->sms.foreign_id); hash = our_hash_func(os); octstr_destroy(os); /* target directory */ dir = octstr_format("%S/%ld", spool_dir, octstr_hash_key(hash) % MAX_DIRS); if (mkdir(octstr_get_cstr(dir), S_IRUSR|S_IWUSR|S_IXUSR) == -1 && errno != EEXIST) { error(errno, "Could not create directory `%s'.", octstr_get_cstr(dir)); octstr_destroy(dir); octstr_destroy(hash); return; } /* * Now also add the hex value of the destination. * This will be the part we look later into while * DLR resolving. */ os = octstr_duplicate(msg->sms.receiver); octstr_binary_to_hex(os, 0); octstr_append(hash, os); octstr_destroy(os); /* target file */ filename = octstr_format("%S/%S", dir, hash); octstr_destroy(dir); octstr_destroy(hash); if ((fd = open(octstr_get_cstr(filename), O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR)) == -1) { error(errno, "Could not open file `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); return; } /* pack and write content to file */ os = store_msg_pack(msg); msg_destroy(msg); for (wrc = 0; wrc < octstr_len(os); ) { size_t rc = write(fd, octstr_get_cstr(os) + wrc, octstr_len(os) - wrc); if (rc == -1) { /* remove file */ error(errno, "Could not write DLR message to `%s'.", octstr_get_cstr(filename)); close(fd); if (unlink(octstr_get_cstr(filename)) == -1) error(errno, "Oops, Could not remove failed file `%s'.", octstr_get_cstr(filename)); octstr_destroy(os); octstr_destroy(filename); return; } wrc += rc; } close(fd); counter_increase(counter); octstr_destroy(filename); octstr_destroy(os); }