int load_add_interval(Load *load, int interval) { int i; struct load_entry *entry; if (load == NULL) return -1; gw_rwlock_wrlock(load->lock); /* first look if we have equal interval added already */ for (i = 0; i < load->len; i++) { if (load->entries[i]->interval == interval) { gw_rwlock_unlock(load->lock); return -1; } } /* so no equal interval there, add new one */ entry = gw_malloc(sizeof(struct load_entry)); entry->prev = entry->curr = 0.0; entry->interval = interval; entry->dirty = 1; time(&entry->last); load->entries = gw_realloc(load->entries, sizeof(struct load*) * (load->len + 1)); load->entries[load->len] = entry; load->len++; gw_rwlock_unlock(load->lock); return 0; }
int log_open(char *filename, int level, enum excl_state excl) { FILE *f = NULL; int i; gw_rwlock_wrlock(&rwlock); if (num_logfiles == MAX_LOGFILES) { gw_rwlock_unlock(&rwlock); error(0, "Too many log files already open, not adding `%s'", filename); return -1; } if (strlen(filename) > FILENAME_MAX) { gw_rwlock_unlock(&rwlock); error(0, "Log filename too long: `%s'.", filename); return -1; } /* * Check if the file is already opened for logging. * If there is an open file, then assign the file descriptor * that is already existing for this log file. */ for (i = 0; i < num_logfiles && f == NULL; ++i) { if (strcmp(logfiles[i].filename, filename) == 0) f = logfiles[i].file; } /* if not previously opened, then open it now */ if (f == NULL) { f = fopen(filename, "a"); if (f == NULL) { gw_rwlock_unlock(&rwlock); error(errno, "Couldn't open logfile `%s'.", filename); return -1; } } logfiles[num_logfiles].file = f; logfiles[num_logfiles].minimum_output_level = level; logfiles[num_logfiles].exclusive = excl; strcpy(logfiles[num_logfiles].filename, filename); ++num_logfiles; i = num_logfiles - 1; gw_rwlock_unlock(&rwlock); info(0, "Added logfile `%s' with level `%d'.", filename, level); return i; }
float load_get(Load *load, int pos) { float ret; time_t now; struct load_entry *entry; if (load == NULL || pos >= load->len) { return -1.0; } /* first maybe rotate load */ load_increase_with(load, 0); time(&now); gw_rwlock_rdlock(load->lock); entry = load->entries[pos]; if (load->heuristic && !entry->dirty) { ret = entry->prev; } else { time_t diff = (now - entry->last); if (diff == 0) diff = 1; ret = entry->curr/diff; } gw_rwlock_unlock(load->lock); return ret; }
void load_increase_with(Load *load, unsigned long value) { time_t now; int i; if (load == NULL) return; gw_rwlock_wrlock(load->lock); time(&now); for (i = 0; i < load->len; i++) { struct load_entry *entry = load->entries[i]; /* check for special case, load over whole live time */ if (entry->interval != -1 && now >= entry->last + entry->interval) { /* rotate */ entry->curr /= entry->interval; if (entry->prev > 0) entry->prev = (2*entry->curr + entry->prev)/3; else entry->prev = entry->curr; entry->last = now; entry->curr = 0.0; entry->dirty = 0; } entry->curr += value; } gw_rwlock_unlock(load->lock); }
int smpp_listener_ip_is_blocked(SMPPServer *smpp_server, Octstr *ip) { int result = 0; long diff, remaining; gw_rwlock_wrlock(smpp_server->ip_blocklist_lock); SMPPBlockedIp *smpp_blocked_ip = dict_get(smpp_server->ip_blocklist, ip); if(smpp_blocked_ip != NULL) { diff = time(NULL) - smpp_blocked_ip->time_blocked; if(diff > smpp_server->ip_blocklist_time) { debug("smpp.listener.ip.is.blocked", 0, "IP address %s is now unblocked", octstr_get_cstr(ip)); /* Time has elapsed, can reset (unblock) */ smpp_blocked_ip->time_blocked = 0; smpp_blocked_ip->attempts = 0; } else { /* Time has not elapsed, how many attempts have they had? */ if(smpp_blocked_ip->attempts >= smpp_server->ip_blocklist_attempts) { result = 1; /* Still blocked */ remaining = smpp_server->ip_blocklist_time - diff; debug("smpp.listener.ip.is.blocked", 0, "IP address %s is blocked for another %ld seconds", octstr_get_cstr(ip), remaining); } } } else { /* Not blocked */ } gw_rwlock_unlock(smpp_server->ip_blocklist_lock); return result; }
void log_close_all(void) { /* * Writer lock. */ gw_rwlock_wrlock(&rwlock); while (num_logfiles > 0) { --num_logfiles; if (logfiles[num_logfiles].file != stderr && logfiles[num_logfiles].file != NULL) fclose(logfiles[num_logfiles].file); logfiles[num_logfiles].file = NULL; } /* * Unlock writer. */ gw_rwlock_unlock(&rwlock); /* close syslog if used */ if (dosyslog) { closelog(); dosyslog = 0; } }
void log_close_all(void) { /* * Writer lock. */ gw_rwlock_wrlock(&rwlock); while (num_logfiles > 0) { --num_logfiles; if (logfiles[num_logfiles].file != stderr && logfiles[num_logfiles].file != NULL) { int i; /* look for the same filename and set file to NULL */ for (i = num_logfiles - 1; i >= 0; i--) { if (strcmp(logfiles[num_logfiles].filename, logfiles[i].filename) == 0) logfiles[i].file = NULL; } fclose(logfiles[num_logfiles].file); logfiles[num_logfiles].file = NULL; } } /* * Unlock writer. */ gw_rwlock_unlock(&rwlock); /* close syslog if used */ if (dosyslog) { closelog(); dosyslog = 0; } }
int load_len(Load *load) { int ret; if (load == NULL) return 0; gw_rwlock_rdlock(load->lock); ret = load->len; gw_rwlock_unlock(load->lock); return ret; }
void smpp_listener_auth_failed(SMPPServer *smpp_server, Octstr *ip) { if (octstr_len(smpp_server->ip_blocklist_exempt_ips) && (octstr_search(smpp_server->ip_blocklist_exempt_ips, ip, 0) > -1)) { debug("smpp.listener.auth.failed", 0, "IP address %s is exempt from the IP block list", octstr_get_cstr(ip)); return; } gw_rwlock_wrlock(smpp_server->ip_blocklist_lock); SMPPBlockedIp *smpp_blocked_ip = dict_get(smpp_server->ip_blocklist, ip); if(smpp_blocked_ip == NULL) { smpp_blocked_ip = smpp_blocked_ip_create(); dict_put(smpp_server->ip_blocklist, ip, smpp_blocked_ip); } smpp_blocked_ip->attempts++; smpp_blocked_ip->time_blocked = time(NULL); debug("smpp.listener.auth.failed", 0, "IP address %s, attempts %ld have failed", octstr_get_cstr(ip), smpp_blocked_ip->attempts); gw_rwlock_unlock(smpp_server->ip_blocklist_lock); }
void smpp_route_rebuild_database(SMPPServer *smpp_server) { info(0, "Rebuilding database routes"); SMPPRouting *smpp_routing = smpp_server->routing; List *inbound_routes = smpp_database_get_routes(smpp_server, SMPP_ROUTE_DIRECTION_INBOUND, NULL); /* Only inbound are built, outbound are built when ESME's connect */ List *old_inbound; Dict *old_outbound; gw_rwlock_wrlock(smpp_routing->lock); old_inbound = smpp_routing->inbound_routes; old_outbound = smpp_routing->outbound_routes; smpp_routing->inbound_routes = inbound_routes; smpp_routing->outbound_routes = dict_create(1024, (void(*)(void *))smpp_outbound_routes_destroy); /* Just reset, they will repopulate on their own */ gw_rwlock_unlock(smpp_routing->lock); gwlist_destroy(old_inbound, (void(*)(void *))smpp_route_destroy); dict_destroy(old_outbound); }
void log_reopen(void) { int i, j, found; /* * Writer lock. */ gw_rwlock_wrlock(&rwlock); for (i = 0; i < num_logfiles; ++i) { if (logfiles[i].file != stderr) { found = 0; /* * Reverse seek for allready reopened logfile. * If we find a previous file descriptor for the same file * name, then don't reopen that duplicate, but assign the * file pointer to it. */ for (j = i-1; j >= 0 && found == 0; j--) { if (strcmp(logfiles[i].filename, logfiles[j].filename) == 0) { logfiles[i].file = logfiles[j].file; found = 1; } } if (found) continue; if (logfiles[i].file != NULL) fclose(logfiles[i].file); logfiles[i].file = fopen(logfiles[i].filename, "a"); if (logfiles[i].file == NULL) { error(errno, "Couldn't re-open logfile `%s'.", logfiles[i].filename); } } } /* * Unlock writer. */ gw_rwlock_unlock(&rwlock); }
static void run_smsbox(void *arg) { Boxc *newconn; long sender; Msg *msg; List *keys; Octstr *key; gwlist_add_producer(flow_threads); newconn = arg; newconn->incoming = gwlist_create(); gwlist_add_producer(newconn->incoming); newconn->retry = incoming_sms; newconn->outgoing = outgoing_sms; newconn->sent = dict_create(smsbox_max_pending, NULL); newconn->pending = semaphore_create(smsbox_max_pending); sender = gwthread_create(boxc_sender, newconn); if (sender == -1) { error(0, "Failed to start a new thread, disconnecting client <%s>", octstr_get_cstr(newconn->client_ip)); goto cleanup; } /* * We register newconn in the smsbox_list here but mark newconn as routable * after identification or first message received from smsbox. So we can avoid * a race condition for routable smsboxes (otherwise between startup and * registration we will forward some messages to smsbox). */ gw_rwlock_wrlock(smsbox_list_rwlock); gwlist_append(smsbox_list, newconn); gw_rwlock_unlock(smsbox_list_rwlock); gwlist_add_producer(newconn->outgoing); boxc_receiver(newconn); gwlist_remove_producer(newconn->outgoing); /* remove us from smsbox routing list */ gw_rwlock_wrlock(smsbox_list_rwlock); gwlist_delete_equal(smsbox_list, newconn); if (newconn->boxc_id) { dict_remove(smsbox_by_id, newconn->boxc_id); } gw_rwlock_unlock(smsbox_list_rwlock); /* * check if we in the shutdown phase and sms dequeueing thread * has removed the producer already */ if (gwlist_producer_count(newconn->incoming) > 0) gwlist_remove_producer(newconn->incoming); /* check if we are still waiting for ack's and semaphore locked */ if (dict_key_count(newconn->sent) >= smsbox_max_pending) semaphore_up(newconn->pending); /* allow sender to go down */ gwthread_join(sender); /* put not acked msgs into incoming queue */ keys = dict_keys(newconn->sent); while((key = gwlist_extract_first(keys)) != NULL) { msg = dict_remove(newconn->sent, key); gwlist_produce(incoming_sms, msg); octstr_destroy(key); } gw_assert(gwlist_len(keys) == 0); gwlist_destroy(keys, octstr_destroy_item); /* clear our send queue */ while((msg = gwlist_extract_first(newconn->incoming)) != NULL) { gwlist_produce(incoming_sms, msg); } cleanup: gw_assert(gwlist_len(newconn->incoming) == 0); gwlist_destroy(newconn->incoming, NULL); gw_assert(dict_key_count(newconn->sent) == 0); dict_destroy(newconn->sent); semaphore_destroy(newconn->pending); boxc_destroy(newconn); /* wakeup the dequeueing thread */ gwthread_wakeup(sms_dequeue_thread); gwlist_remove_producer(flow_threads); }
static void sms_to_smsboxes(void *arg) { Msg *newmsg, *startmsg, *msg; long i, len; int ret = -1; Boxc *boxc; gwlist_add_producer(flow_threads); newmsg = startmsg = msg = NULL; while(bb_status != BB_DEAD) { if (newmsg == startmsg) { /* check if we are in shutdown phase */ if (gwlist_producer_count(smsbox_list) == 0) break; if (ret == 0 || ret == -1) { /* debug("", 0, "time to sleep"); */ gwthread_sleep(60.0); /* debug("", 0, "wake up list len %ld", gwlist_len(incoming_sms)); */ /* shutdown ? */ if (gwlist_producer_count(smsbox_list) == 0 && gwlist_len(smsbox_list) == 0) break; } startmsg = msg = gwlist_consume(incoming_sms); /* debug("", 0, "gwlist_consume done 1"); */ newmsg = NULL; } else { newmsg = msg = gwlist_consume(incoming_sms); /* Back at the first message? */ if (newmsg == startmsg) { gwlist_insert(incoming_sms, 0, msg); continue; } } if (msg == NULL) break; gw_assert(msg_type(msg) == sms); /* debug("bb.sms", 0, "sms_boxc_router: handling message (%p vs %p)", msg, startmsg); */ ret = route_incoming_to_boxc(msg); if (ret == 1) startmsg = newmsg = NULL; else if (ret == -1) { gwlist_produce(incoming_sms, msg); } } gw_rwlock_rdlock(smsbox_list_rwlock); len = gwlist_len(smsbox_list); for (i=0; i < len; i++) { boxc = gwlist_get(smsbox_list, i); gwlist_remove_producer(boxc->incoming); } gw_rwlock_unlock(smsbox_list_rwlock); gwlist_remove_producer(flow_threads); }
/* * Route the incoming message to one of the following input queues: * a specific smsbox conn * a random smsbox conn if no shortcut routing and msg->sms.boxc_id match * * BEWARE: All logic inside here should be fast, hence speed processing * optimized, because every single MO message passes this function and we * have to ensure that no unncessary overhead is done. */ int route_incoming_to_boxc(Msg *msg) { Boxc *bc = NULL, *best = NULL; Octstr *s, *r, *rs; long len, b, i; int full_found = 0; s = r = NULL; gw_assert(msg_type(msg) == sms); /* msg_dump(msg, 0); */ /* * We have a specific route to pass this msg to smsbox-id * Lookup the connection in the dictionary. */ gw_rwlock_rdlock(smsbox_list_rwlock); if (gwlist_len(smsbox_list) == 0) { gw_rwlock_unlock(smsbox_list_rwlock); warning(0, "smsbox_list empty!"); if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) { gwlist_produce(incoming_sms, msg); return 0; } else return -1; } if (octstr_len(msg->sms.boxc_id) > 0) { bc = dict_get(smsbox_by_id, msg->sms.boxc_id); if (bc == NULL) { /* * something is wrong, this was the smsbox connection we used * for sending, so it seems this smsbox is gone */ warning(0,"Could not route message to smsbox id <%s>, smsbox is gone!", octstr_get_cstr(msg->sms.boxc_id)); } } else { /* * Check if we have a "smsbox-route" for this msg. * Where the shortcode route has a higher priority then the smsc-id rule. * Highest priority has the combined <shortcode>:<smsc-id> route. */ Octstr *os = octstr_format("%s:%s", octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.smsc_id)); s = (msg->sms.smsc_id ? dict_get(smsbox_by_smsc, msg->sms.smsc_id) : NULL); r = (msg->sms.receiver ? dict_get(smsbox_by_receiver, msg->sms.receiver) : NULL); rs = (os ? dict_get(smsbox_by_smsc_receiver, os) : NULL); octstr_destroy(os); bc = rs ? dict_get(smsbox_by_id, rs) : (r ? dict_get(smsbox_by_id, r) : (s ? dict_get(smsbox_by_id, s) : NULL)); } /* check if we found our routing */ if (bc != NULL) { if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(bc->incoming)) { gwlist_produce(bc->incoming, msg); gw_rwlock_unlock(smsbox_list_rwlock); return 1; /* we are done */ } else { gw_rwlock_unlock(smsbox_list_rwlock); return -1; } } else if (s != NULL || r != NULL || octstr_len(msg->sms.boxc_id) > 0) { gw_rwlock_unlock(smsbox_list_rwlock); /* * we have routing defined, but no smsbox connected at the moment. * put msg into global incoming queue and wait until smsbox with * such boxc_id connected. */ if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) { gwlist_produce(incoming_sms, msg); return 0; } else return -1; } /* * ok, none of the routing things applied previously, so route it to * a random smsbox. */ /* take random smsbox from list, and then check all smsboxes * and select the one with lowest load level - if tied, the first * one */ len = gwlist_len(smsbox_list); b = gw_rand() % len; for(i = 0; i < gwlist_len(smsbox_list); i++) { bc = gwlist_get(smsbox_list, (i+b) % len); if (bc->boxc_id != NULL || bc->routable == 0) bc = NULL; if (bc != NULL && max_incoming_sms_qlength > 0 && gwlist_len(bc->incoming) > max_incoming_sms_qlength) { full_found = 1; bc = NULL; } if ((bc != NULL && best != NULL && bc->load < best->load) || (bc != NULL && best == NULL)) { best = bc; } } if (best != NULL) { best->load++; gwlist_produce(best->incoming, msg); } gw_rwlock_unlock(smsbox_list_rwlock); if (best == NULL && full_found == 0) { warning(0, "smsbox_list empty!"); if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) { gwlist_produce(incoming_sms, msg); return 0; } else return -1; } else if (best == NULL && full_found == 1) return -1; return 1; }
Octstr *boxc_status(int status_type) { Octstr *tmp; char *lb, *ws; int i, boxes, para = 0; time_t orig, t; Boxc *bi; orig = time(NULL); /* * XXX: this will cause segmentation fault if this is called * between 'destroy_list and setting list to NULL calls. * Ok, this has to be fixed, but now I am too tired. */ if ((lb = bb_status_linebreak(status_type))==NULL) return octstr_create("Un-supported format"); if (status_type == BBSTATUS_HTML) ws = " "; else if (status_type == BBSTATUS_TEXT) ws = " "; else ws = ""; if (status_type == BBSTATUS_HTML || status_type == BBSTATUS_WML) para = 1; if (status_type == BBSTATUS_XML) { tmp = octstr_create (""); octstr_append_cstr(tmp, "<boxes>\n\t"); } else tmp = octstr_format("%sBox connections:%s", para ? "<p>" : "", lb); boxes = 0; if (wapbox_list) { gwlist_lock(wapbox_list); for(i=0; i < gwlist_len(wapbox_list); i++) { bi = gwlist_get(wapbox_list, i); if (bi->alive == 0) continue; t = orig - bi->connect_time; if (status_type == BBSTATUS_XML) octstr_format_append(tmp, "<box>\n\t\t<type>wapbox</type>\n\t\t<IP>%s</IP>\n" "\t\t<status>on-line %ldd %ldh %ldm %lds</status>\n" "\t\t<ssl>%s</ssl>\n\t</box>\n", octstr_get_cstr(bi->client_ip), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "yes" : "no" #else "not installed" #endif ); else octstr_format_append(tmp, "%swapbox, IP %s (on-line %ldd %ldh %ldm %lds) %s %s", ws, octstr_get_cstr(bi->client_ip), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "using SSL" : "", #else "", #endif lb); boxes++; } gwlist_unlock(wapbox_list); } if (smsbox_list) { gw_rwlock_rdlock(smsbox_list_rwlock); for(i=0; i < gwlist_len(smsbox_list); i++) { bi = gwlist_get(smsbox_list, i); if (bi->alive == 0) continue; t = orig - bi->connect_time; if (status_type == BBSTATUS_XML) octstr_format_append(tmp, "<box>\n\t\t<type>smsbox</type>\n" "\t\t<id>%s</id>\n\t\t<IP>%s</IP>\n" "\t\t<queue>%ld</queue>\n" "\t\t<status>on-line %ldd %ldh %ldm %lds</status>\n" "\t\t<ssl>%s</ssl>\n\t</box>", (bi->boxc_id ? octstr_get_cstr(bi->boxc_id) : ""), octstr_get_cstr(bi->client_ip), gwlist_len(bi->incoming) + dict_key_count(bi->sent), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "yes" : "no" #else "not installed" #endif ); else octstr_format_append(tmp, "%ssmsbox:%s, IP %s (%ld queued), (on-line %ldd %ldh %ldm %lds) %s %s", ws, (bi->boxc_id ? octstr_get_cstr(bi->boxc_id) : "(none)"), octstr_get_cstr(bi->client_ip), gwlist_len(bi->incoming) + dict_key_count(bi->sent), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "using SSL" : "", #else "", #endif lb); boxes++; } gw_rwlock_unlock(smsbox_list_rwlock); } if (boxes == 0 && status_type != BBSTATUS_XML) { octstr_destroy(tmp); tmp = octstr_format("%sNo boxes connected", para ? "<p>" : ""); } if (para) octstr_append_cstr(tmp, "</p>"); if (status_type == BBSTATUS_XML) octstr_append_cstr(tmp, "</boxes>\n"); else octstr_append_cstr(tmp, "\n\n"); return tmp; }
int log_open(char *filename, int level, enum excl_state excl, char *do_rotatelog) { FILE *f = NULL; int i; gw_rwlock_wrlock(&rwlock); rotatelog = gw_strdup(do_rotatelog); if (num_logfiles == MAX_LOGFILES) { gw_rwlock_unlock(&rwlock); error(0, "Too many log files already open, not adding `%s'", filename); return -1; } if (strlen(filename) > FILENAME_MAX) { gw_rwlock_unlock(&rwlock); error(0, "Log filename too long: `%s'.", filename); return -1; } //if (rotate_logfile == NEVER && rotatelog && *rotatelog) { if (rotatelog && *rotatelog) { if (strcmp(rotatelog, "daily") == 0) rotate_logfile = DAILY; else if (strcmp(rotatelog, "weekly") == 0) rotate_logfile = WEEKLY; else if (strcmp(rotatelog, "monthly") == 0) rotate_logfile = MONTHLY; } /* * Check if the file is already opened for logging. * If there is an open file, then assign the file descriptor * that is already existing for this log file. */ for (i = 0; i < num_logfiles && f == NULL; ++i) { if (strcmp(logfiles[i].filename, filename) == 0) f = logfiles[i].file; } /* if not previously opened, then open it now */ if (f == NULL) { f = fopen(filename, "a"); if (f == NULL) { gw_rwlock_unlock(&rwlock); error(errno, "Couldn't open logfile `%s'.", filename); return -1; } } logfiles[num_logfiles].file = f; logfiles[num_logfiles].minimum_output_level = level; logfiles[num_logfiles].exclusive = excl; strcpy(logfiles[num_logfiles].filename, filename); ++num_logfiles; i = num_logfiles - 1; gw_rwlock_unlock(&rwlock); info(0, "Added logfile `%s' with level `%d'. Log rotation: %s. %d.", filename, level, rotatelog ? rotatelog : "never", rotate_logfile); return i; }
void smpp_route_message_database(SMPPServer *smpp_server, int direction, Octstr *smsc_id, Octstr *system_id, Msg *msg, void(*callback)(void *context, int result, double cost), void *context) { SMPPRouting *smpp_routing = smpp_server->routing; List *routes; long i, num_routes; int found = 0; SMPPRoute *route; gw_rwlock_rdlock(smpp_routing->lock); if(msg_type(msg) == sms) { /* we can only route sms's */ if((direction == SMPP_ROUTE_DIRECTION_OUTBOUND) && octstr_len(system_id)) { /* Look for our ESME routes */ gw_rwlock_wrlock(smpp_routing->outbound_lock); routes = dict_get(smpp_routing->outbound_routes, system_id); if(!routes) { routes = smpp_database_get_routes(smpp_server, direction, system_id); dict_put(smpp_routing->outbound_routes, system_id, routes); } gw_rwlock_unlock(smpp_routing->outbound_lock); num_routes = gwlist_len(routes); for(i=0;i<num_routes;i++) { route = gwlist_get(routes, i); found = gw_regex_match_pre(route->regex, msg->sms.receiver); if(found) { break; } } if(found) { octstr_destroy(msg->sms.smsc_id); msg->sms.smsc_id = octstr_duplicate(route->smsc_id); debug("smpp.route.message.database", 0, "SMPP[%s] Found outbound route for %s towards %s", octstr_get_cstr(system_id), octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.smsc_id)); callback(context, 1, route->cost); } else { callback(context, 0, 0); } } else if((direction == SMPP_ROUTE_DIRECTION_INBOUND) && octstr_len(smsc_id)) { routes = smpp_routing->inbound_routes; num_routes = gwlist_len(routes); for(i=0;i<num_routes;i++) { route = gwlist_get(routes, i); found = gw_regex_match_pre(route->regex, msg->sms.receiver); if(found) { break; } } if(found) { octstr_destroy(msg->sms.service); msg->sms.service = octstr_duplicate(route->system_id); debug("smpp.route.message.database", 0, "SMPP[%s] Found inbound route for %s from %s", octstr_get_cstr(route->system_id), octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(smsc_id)); callback(context, 1, route->cost); } else { callback(context, 0, 0); } } else { callback(context, 0, 0); } } else { callback(context, 0, 0); } gw_rwlock_unlock(smpp_routing->lock); }