static struct dlr_entry *dlr_redis_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *key, *sql; DBPoolConn *pconn; List *binds = gwlist_create(); List *result = NULL, *row; struct dlr_entry *res = NULL; pconn = dbpool_conn_consume(pool); if (pconn == NULL) { error(0, "DLR: REDIS: No connection available"); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return NULL; } /* If the destination address is not NULL, then * it has been shortened by the abstractive layer. */ key = octstr_format((dst ? "%S:?:?:?" : "%S:?:?"), fields->table); sql = octstr_format("HMGET %S ? ? ? ? ? ?", key); gwlist_append(binds, (Octstr *)smsc); /* key */ gwlist_append(binds, (Octstr *)ts); /* key */ if (dst) gwlist_append(binds, (Octstr *)dst); /* key */ gwlist_append(binds, fields->field_mask); gwlist_append(binds, fields->field_serv); gwlist_append(binds, fields->field_url); gwlist_append(binds, fields->field_src); gwlist_append(binds, fields->field_dst); gwlist_append(binds, fields->field_boxc); if (dbpool_conn_select(pconn, sql, binds, &result) != 0) { error(0, "DLR: REDIS: Failed to fetch DLR for %s", octstr_get_cstr(key)); octstr_destroy(sql); octstr_destroy(key); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return NULL; } dbpool_conn_produce(pconn); octstr_destroy(sql); octstr_destroy(key); gwlist_destroy(binds, NULL); #define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i)) if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); /* * If we get an empty set back from redis, this is * still an array with "" values, representing (nil). * If the mask is empty then this can't be a valid * set, therefore bail out. */ if (octstr_len(gwlist_get(row, 0)) > 0) { res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(octstr_get_cstr(gwlist_get(row, 0))); get_octstr_value(&res->service, row, 1); get_octstr_value(&res->url, row, 2); octstr_url_decode(res->url); get_octstr_value(&res->source, row, 3); get_octstr_value(&res->destination, row, 4); get_octstr_value(&res->boxc_id, row, 5); res->smsc = octstr_duplicate(smsc); octstr_replace(res->source, octstr_imm("__space__"), octstr_imm(" ")); octstr_replace(res->destination, octstr_imm("__space__"), octstr_imm(" ")); } gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); #undef LO2CSTR return res; }
struct dlr_storage *dlr_init_redis(Cfg *cfg) { CfgGroup *grp; List *grplist; Octstr *redis_host, *redis_pass, *redis_id; long redis_port = 0, redis_database = -1, redis_idle_timeout = -1; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * Check for all mandatory directives that specify the field names * of the used Redis key */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db")))) panic(0, "DLR: Redis: group 'dlr-db' is not specified!"); if (!(redis_id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: Redis: directive 'id' is not specified!"); fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); /* * Escaping special quotes for field/table names */ octstr_replace(fields->table, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_smsc, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_ts, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_src, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_dst, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_serv, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_url, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_mask, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_status, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_boxc, octstr_imm("`"), octstr_imm("``")); /* * Now grab the required information from the 'redis-connection' group * with the redis-id we just obtained. * * We have to loop through all available Redis connection definitions * and search for the one we are looking for. */ grplist = cfg_get_multi_group(cfg, octstr_imm("redis-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, redis_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "DLR: Redis: connection settings for id '%s' are not specified!", octstr_get_cstr(redis_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(redis_host = cfg_get(grp, octstr_imm("host")))) panic(0, "DLR: Redis: directive 'host' is not specified!"); if (cfg_get_integer(&redis_port, grp, octstr_imm("port")) == -1) panic(0, "DLR: Redis: directive 'port' is not specified!"); redis_pass = cfg_get(grp, octstr_imm("password")); cfg_get_integer(&redis_database, grp, octstr_imm("database")); cfg_get_integer(&redis_idle_timeout, grp, octstr_imm("idle-timeout")); /* * Ok, ready to connect to Redis */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->redis = gw_malloc(sizeof(RedisConf)); gw_assert(db_conf->redis != NULL); db_conf->redis->host = redis_host; db_conf->redis->port = redis_port; db_conf->redis->password = redis_pass; db_conf->redis->database = redis_database; db_conf->redis->idle_timeout = redis_idle_timeout; pool = dbpool_create(DBPOOL_REDIS, db_conf, pool_size); gw_assert(pool != NULL); /* * Panic on failure to connect. Should we just try to reconnect? */ if (dbpool_conn_count(pool) == 0) panic(0,"DLR: Redis: database pool has no connections!"); octstr_destroy(redis_id); return &handles; }
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); }
/* MT related function */ static int brunet_send_sms(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; Octstr *url, *tid, *xser; List *headers; char id[UUID_STR_LEN + 1]; int dcs; /* * Construct TransactionId. * Beware that brunet needs an "clean" octstr representation, * without the dashes in the string. So remove them. */ uuid_unparse(sms->sms.id, id); tid = octstr_create(id); octstr_replace(tid, octstr_imm("-"), octstr_imm("")); /* form the basic URL */ url = octstr_format("%S?MsIsdn=%E&Originator=%E", conndata->send_url, sms->sms.receiver, sms->sms.sender); /* * We use &binfo=<foobar> from sendsms interface to encode * additional paramters. If a mandatory value is not set, * a default value is applied */ if (octstr_len(sms->sms.binfo)) { octstr_url_decode(sms->sms.binfo); octstr_format_append(url, "&%S", sms->sms.binfo); } /* CustomerId */ if (octstr_search(url, octstr_create("CustomerId="), 0) == -1) { octstr_format_append(url, "&CustomerId=%S", conndata->username); } /* TransactionId */ if (octstr_search(url, octstr_create("TransactionId="), 0) == -1) { octstr_format_append(url, "&TransactionId=%S", tid); } /* SMSCount */ if (octstr_search(url, octstr_create("SMSCount="), 0) == -1) { octstr_format_append(url, "&%s", "SMSCount=1"); } /* ActionType */ if (octstr_search(url, octstr_create("ActionType="), 0) == -1) { octstr_format_append(url, "&%s", "ActionType=A"); } /* ServiceDeliveryType */ if (octstr_search(url, octstr_create("ServiceDeliveryType="), 0) == -1) { octstr_format_append(url, "&%s", "ServiceDeliveryType=P"); } /* if coding is not set and UDH exists, assume DC_8BIT * else default to DC_7BIT */ if (sms->sms.coding == DC_UNDEF) sms->sms.coding = octstr_len(sms->sms.udhdata) > 0 ? DC_8BIT : DC_7BIT; if (sms->sms.coding == DC_8BIT) octstr_format_append(url, "&MessageType=B&Text=%H", sms->sms.msgdata); else octstr_format_append(url, "&MessageType=S&Text=%E", sms->sms.msgdata); dcs = fields_to_dcs(sms, (sms->sms.alt_dcs != SMS_PARAM_UNDEFINED ? sms->sms.alt_dcs : 0)); /* XSer processing */ xser = octstr_create(""); /* XSer DCS values */ if (dcs != 0 && dcs != 4) octstr_format_append(xser, "0201%02x", dcs & 0xff); /* add UDH header */ if (octstr_len(sms->sms.udhdata)) { octstr_format_append(xser, "01%02x%H", octstr_len(sms->sms.udhdata), sms->sms.udhdata); } if (octstr_len(xser) > 0) octstr_format_append(url, "&XSer=%S", xser); octstr_destroy(xser); headers = http_create_empty_headers(); debug("smsc.http.brunet", 0, "HTTP[%s]: Sending request <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(url)); /* * Brunet requires an SSL-enabled HTTP client call, this is handled * transparently by the Kannel HTTP layer module. */ http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, NULL, 0, sms, NULL); octstr_destroy(url); octstr_destroy(tid); http_destroy_headers(headers); return 0; }
struct dlr_storage *dlr_init_pgsql(Cfg *cfg) { CfgGroup *grp; List *grplist; Octstr *pgsql_host, *pgsql_user, *pgsql_pass, *pgsql_db, *pgsql_id; long pgsql_port = 0; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * check for all mandatory directives that specify the field names * of the table used */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db")))) panic(0, "DLR: PgSQL: group 'dlr-db' is not specified!"); if (!(pgsql_id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: PgSQL: directive 'id' is not specified!"); fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); /* * Escaping special quotes for field/table names */ octstr_replace(fields->table, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_smsc, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_ts, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_src, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_dst, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_serv, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_url, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_mask, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_status, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_boxc, octstr_imm("\""), octstr_imm("\"\"")); /* * now grap the required information from the 'pgsql-connection' group * with the pgsql-id we just obtained * * we have to loop through all available PostgreSQL connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("pgsql-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, pgsql_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "DLR: PgSQL: connection settings for id '%s' are not specified!", octstr_get_cstr(pgsql_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(pgsql_host = cfg_get(grp, octstr_imm("host")))) panic(0, "DLR: PgSQL: directive 'host' is not specified!"); if (!(pgsql_user = cfg_get(grp, octstr_imm("username")))) panic(0, "DLR: PgSQL: directive 'username' is not specified!"); if (!(pgsql_pass = cfg_get(grp, octstr_imm("password")))) panic(0, "DLR: PgSQL: directive 'password' is not specified!"); if (!(pgsql_db = cfg_get(grp, octstr_imm("database")))) panic(0, "DLR: PgSQL: directive 'database' is not specified!"); cfg_get_integer(&pgsql_port, grp, octstr_imm("port")); /* optional */ /* * ok, ready to connect to the database */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->pgsql = gw_malloc(sizeof(PgSQLConf)); gw_assert(db_conf->pgsql != NULL); db_conf->pgsql->host = pgsql_host; db_conf->pgsql->port = pgsql_port; db_conf->pgsql->username = pgsql_user; db_conf->pgsql->password = pgsql_pass; db_conf->pgsql->database = pgsql_db; pool = dbpool_create(DBPOOL_PGSQL, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"DLR: PgSQL: database pool has no connections!"); octstr_destroy(pgsql_id); return &handles; }
int mms_mmbox_modmsg(char *mmbox_root, char *user, Octstr *msgref, Octstr *state, List *flag_cmds) { Octstr *sdf = octstr_duplicate(msgref); Octstr *fname = NULL, *ftmp = NULL; Octstr *home = user_mmbox_dir(mmbox_root,user); Octstr *s = NULL; List *flags = NULL; Octstr *nstate = NULL; int ifd = -1, nifd, tmpfd = -1; MmsMsg *m = NULL; int res = -1; int msize; octstr_replace(sdf, octstr_imm("-"), octstr_imm("/")); if (!home) goto done; ifd = open_mmbox_index(octstr_get_cstr(home),1); if (ifd < 0) goto done; fname = octstr_format("%S/%S", home, sdf); s = octstr_read_file(octstr_get_cstr(fname)); if ( s == NULL || octstr_len(s) == 0) { error(0, "mmbox.mod: failed to read data file [%s] - %s!", octstr_get_cstr(fname), strerror(errno)); goto done; } m = mms_frombinary(s, octstr_imm("anon@anon")); if (!m) { error(0, "mmbox.mod: failed to read data file [%s]!", octstr_get_cstr(fname)); goto done; } if (state == NULL) nstate = mms_get_header_value(m, octstr_imm("X-Mms-MM-State")); else { nstate = octstr_duplicate(state); mms_replace_header_value(m, "X-Mms-MM-State", octstr_get_cstr(nstate)); } flags = mms_get_header_values(m, octstr_imm("X-Mms-MM-Flags")); flags = make_mm_flags(flags, flag_cmds); mms_replace_header_values(m, "X-Mms-MM-Flags", flags); ftmp = octstr_format("%S.%ld.%d", fname, time(NULL), getpid()); tmpfd = open(octstr_get_cstr(ftmp), O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (tmpfd < 0) goto done; s = mms_tobinary(m); msize = octstr_len(s); octstr_write_to_socket(tmpfd, s); rename(octstr_get_cstr(ftmp), octstr_get_cstr(fname)); unlock_and_close(tmpfd); if ((nifd = update_mmbox_index(ifd, octstr_get_cstr(home), ITEM_MOD, sdf, nstate, flags, msize)) < 0) { /* Not good, we wrote but could not update the index file. scream. */ error(0, "mmbox.mod: failed to update index file, home is %s!", octstr_get_cstr(home)); goto done; } ifd = nifd; res = 0; done: if (ifd > 0) unlock_and_close(ifd); if (fname) octstr_destroy(fname); if (ftmp) octstr_destroy(ftmp); if (sdf) octstr_destroy(sdf); if (s) octstr_destroy(s); if (home) octstr_destroy(home); if (nstate) octstr_destroy(nstate); if (flags) gwlist_destroy(flags, (gwlist_item_destructor_t *)octstr_destroy); if (m) mms_destroy(m); return res; }
Octstr *mms_mmbox_addmsg(char *mmbox_root, char *user, MmsMsg *msg, List *flag_cmds, Octstr *dfltstate) { int ifd = -1, nifd, dfd = -1; char df[128]; Octstr *home = user_mmbox_dir(mmbox_root,user); Octstr *s = octstr_create(""), *sdf = NULL; List *flags = NULL; Octstr *state = NULL; int msize; if (!home) goto done; ifd = open_mmbox_index(octstr_get_cstr(home),1); if (ifd < 0) goto done; if ((dfd = mkdf(df, octstr_get_cstr(home))) < 0) { error(0, "mmbox_add: failed to create data file, home=%s - %s!", octstr_get_cstr(home), strerror(errno)); goto done; } state = mms_get_header_value(msg, octstr_imm("X-Mms-MM-State")); flags = make_mm_flags(mms_get_header_values(msg, octstr_imm("X-Mms-MM-Flags")), flag_cmds); if (state == NULL) state = dfltstate ? octstr_duplicate(dfltstate) : octstr_create("Sent"); mms_replace_header_values(msg, "X-Mms-MM-Flags", flags); mms_replace_header_value(msg, "X-Mms-MM-State", octstr_get_cstr(state)); s = mms_tobinary(msg); msize = octstr_len(s); octstr_write_to_socket(dfd, s); sdf = octstr_create(df); if ((nifd = update_mmbox_index(ifd, octstr_get_cstr(home), ITEM_ADD, sdf, state, flags, msize)) < 0 ) { char fbuf[256]; sprintf(fbuf, "%s/%s", octstr_get_cstr(home), df); unlink(fbuf); octstr_destroy(sdf); sdf = NULL; goto done; } ifd = nifd; octstr_replace(sdf, octstr_imm("/"), octstr_imm("-")); done: if (dfd > 0) unlock_and_close(dfd); if (ifd > 0) unlock_and_close(ifd); if (s) octstr_destroy(s); if (home) octstr_destroy(home); if (state) octstr_destroy(state); if (flags) gwlist_destroy(flags, (gwlist_item_destructor_t *)octstr_destroy); return sdf; }