unsigned int dbpool_decrease(DBPool *p, unsigned int c) { unsigned int i; gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL && p->db_ops->close != NULL); /* lock dbpool for updates */ gwlist_lock(p->pool); /* * Ensure we don't try to decrease more then available in pool. */ for (i = 0; i < c; i++) { DBPoolConn *pc; /* gwlist_extract_first doesn't block even if no conn here */ pc = gwlist_extract_first(p->pool); /* no conn availible anymore */ if (pc == NULL) break; /* close connections and destroy pool connection */ dbpool_conn_destroy(pc); p->curr_size--; } /* unlock dbpool for updates */ gwlist_unlock(p->pool); return i; }
unsigned int dbpool_increase(DBPool *p, unsigned int count) { unsigned int i, opened = 0; gw_assert(p != NULL && p->conf != NULL && p->db_ops != NULL && p->db_ops->open != NULL); /* lock dbpool for updates */ gwlist_lock(p->pool); /* ensure we don't increase more items than the max_size border */ for (i=0; i < count && p->curr_size < p->max_size; i++) { void *conn = p->db_ops->open(p->conf); if (conn != NULL) { DBPoolConn *pc = gw_malloc(sizeof(DBPoolConn)); gw_assert(pc != NULL); pc->conn = conn; pc->pool = p; p->curr_size++; opened++; gwlist_produce(p->pool, pc); } } /* unlock dbpool for updates */ gwlist_unlock(p->pool); return opened; }
static void run_wapbox(void *arg) { Boxc *newconn; List *newlist; long sender; gwlist_add_producer(flow_threads); newconn = arg; newconn->is_wap = 1; /* * create a new incoming list for just that box, * and add it to list of list pointers, so we can start * to route messages to it. */ debug("bb", 0, "setting up systems for new wapbox"); newlist = gwlist_create(); /* this is released by the sender/receiver if it exits */ gwlist_add_producer(newlist); newconn->incoming = newlist; newconn->retry = incoming_wdp; newconn->outgoing = outgoing_wdp; 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; } gwlist_append(wapbox_list, newconn); gwlist_add_producer(newconn->outgoing); boxc_receiver(newconn); /* cleanup after receiver has exited */ gwlist_remove_producer(newconn->outgoing); gwlist_lock(wapbox_list); gwlist_delete_equal(wapbox_list, newconn); gwlist_unlock(wapbox_list); while (gwlist_producer_count(newlist) > 0) gwlist_remove_producer(newlist); newconn->alive = 0; gwthread_join(sender); cleanup: gw_assert(gwlist_len(newlist) == 0); gwlist_destroy(newlist, NULL); boxc_destroy(newconn); gwlist_remove_producer(flow_threads); }
DBPoolConn *dbpool_conn_consume(DBPool *p) { DBPoolConn *pc; gw_assert(p != NULL && p->pool != NULL); /* check for max connections and if 0 return NULL */ if (p->max_size < 1) return NULL; /* check if we have any connection */ while (p->curr_size < 1) { debug("dbpool", 0, "DBPool has no connections, reconnecting up to maximum..."); /* dbpool_increase ensure max_size is not exceeded so don't lock */ dbpool_increase(p, p->max_size - p->curr_size); if (p->curr_size < 1) gwthread_sleep(0.1); } /* garantee that you deliver a valid connection to the caller */ while ((pc = gwlist_consume(p->pool)) != NULL) { /* * XXX check that the connection is still existing. * Is this a performance bottle-neck?! */ if (!pc->conn || (p->db_ops->check && p->db_ops->check(pc->conn) != 0)) { /* something was wrong, reinitialize the connection */ /* lock dbpool for update */ gwlist_lock(p->pool); dbpool_conn_destroy(pc); p->curr_size--; /* unlock dbpool for update */ gwlist_unlock(p->pool); /* * maybe not needed, just try to get next connection, but it * can be dangeros if all connections where broken, then we will * block here for ever. */ while (p->curr_size < 1) { debug("dbpool", 0, "DBPool has too few connections, reconnecting up to maximum..."); /* dbpool_increase ensure max_size is not exceeded so don't lock */ dbpool_increase(p, p->max_size - p->curr_size); if (p->curr_size < 1) gwthread_sleep(0.1); } } else { break; } } return (pc->conn != NULL ? pc : NULL); }
/* * this function receives an WDP message and adds it to * corresponding outgoing_list. */ int udp_addwdp(Msg *msg) { int i; Udpc *udpc, *def_udpc; Octstr *ip; def_udpc = NULL; if (!udp_running) return -1; assert(msg != NULL); assert(msg_type(msg) == wdp_datagram); gwlist_lock(udpc_list); /* select in which list to add this */ for (i=0; i < gwlist_len(udpc_list); i++) { udpc = gwlist_get(udpc_list, i); if (msg->wdp_datagram.source_port == udp_get_port(udpc->addr)) { def_udpc = udpc; ip = udp_get_ip(udpc->addr); if (octstr_compare(msg->wdp_datagram.source_address, ip) == 0) { octstr_destroy(ip); gwlist_produce(udpc->outgoing_list, msg); gwlist_unlock(udpc_list); return 0; } octstr_destroy(ip); } } if (NULL != def_udpc) { gwlist_produce(def_udpc->outgoing_list, msg); gwlist_unlock(udpc_list); return 0; } gwlist_unlock(udpc_list); return -1; }
/* * this thread listens to incoming_wdp list * and then routs messages to proper wapbox */ static void wdp_to_wapboxes(void *arg) { List *route_info; AddrPar *ap; Boxc *conn; Msg *msg; int i; gwlist_add_producer(flow_threads); gwlist_add_producer(wapbox_list); route_info = gwlist_create(); while(bb_status != BB_DEAD) { gwlist_consume(suspended); /* block here if suspended */ if ((msg = gwlist_consume(incoming_wdp)) == NULL) break; gw_assert(msg_type(msg) == wdp_datagram); conn = route_msg(route_info, msg); if (conn == NULL) { warning(0, "Cannot route message, discard it"); msg_destroy(msg); continue; } gwlist_produce(conn->incoming, msg); } debug("bb", 0, "wdp_to_wapboxes: destroying lists"); while((ap = gwlist_extract_first(route_info)) != NULL) ap_destroy(ap); gw_assert(gwlist_len(route_info) == 0); gwlist_destroy(route_info, NULL); gwlist_lock(wapbox_list); for(i=0; i < gwlist_len(wapbox_list); i++) { conn = gwlist_get(wapbox_list, i); gwlist_remove_producer(conn->incoming); conn->alive = 0; } gwlist_unlock(wapbox_list); gwlist_remove_producer(wapbox_list); gwlist_remove_producer(flow_threads); }
static Udpc *udpc_find_mapping(Msg *msg, int inbound) { int i; Udpc *udpc; Octstr *addr; /* check if there is allready a bound UDP port */ gwlist_lock(udpc_list); for (i=0; i < gwlist_len(udpc_list); i++) { udpc = gwlist_get(udpc_list, i); /* decide if we compare against inbound or outbound traffic mapping */ addr = inbound ? udpc->map_addr : udpc->addr; if (msg->wdp_datagram.source_port == udp_get_port(addr) && octstr_compare(msg->wdp_datagram.source_address, udp_get_ip(addr)) == 0) { gwlist_unlock(udpc_list); return udpc; } } gwlist_unlock(udpc_list); return NULL; }
int boxc_incoming_wdp_queue(void) { int i, q = 0; Boxc *boxc; if (wapbox_list) { gwlist_lock(wapbox_list); for(i=0; i < gwlist_len(wapbox_list); i++) { boxc = gwlist_get(wapbox_list, i); q += gwlist_len(boxc->incoming); } gwlist_unlock(wapbox_list); } return q; }
int udp_outgoing_queue(void) { int i, q = 0; Udpc *udpc; if (!udp_running || udpc_list == NULL) return 0; gwlist_lock(udpc_list); for (i=0; i < gwlist_len(udpc_list); i++) { udpc = gwlist_get(udpc_list, i); q += gwlist_len(udpc->outgoing_list); } gwlist_unlock(udpc_list); return q; }
void alog_close(void) { if (file != NULL) { if (markers) alog("Log ends"); gwlist_lock(writers); /* wait for writers to complete */ gwlist_consume(writers); fclose(file); file = NULL; gwlist_unlock(writers); gwlist_destroy(writers, NULL); writers = NULL; } }
int gw_rwlock_rdlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_rdlock(&lock->rwlock); if (ret != 0) { panic(ret, "Error while pthread_rwlock_rdlock."); } #else gwlist_lock(lock->rwlock); gwlist_add_producer(lock->rwlock); gwlist_unlock(lock->rwlock); RWDEBUG("", 0, "------------ gw_rwlock_rdlock(%p) ----------", lock); #endif return ret; }
int gw_rwlock_unlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_unlock(&lock->rwlock); if (ret != 0) panic(ret, "Error while gw_rwlock_unlock."); #else RWDEBUG("", 0, "------------ gw_rwlock_unlock(%p) ----------", lock); if (lock->writer == gwthread_self()) { lock->writer = -1; gwlist_unlock(lock->rwlock); } else gwlist_remove_producer(lock->rwlock); #endif return ret; }
unsigned int dbpool_check(DBPool *p) { long i, len, n = 0, reinit = 0; gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL); /* * First check if db_ops->check function pointer is here. * NOTE: db_ops->check is optional, so if it is not there, then * we have nothing todo and we simple return list length. */ if (p->db_ops->check == NULL) return gwlist_len(p->pool); gwlist_lock(p->pool); len = gwlist_len(p->pool); for (i = 0; i < len; i++) { DBPoolConn *pconn; pconn = gwlist_get(p->pool, i); if (p->db_ops->check(pconn->conn) != 0) { /* something was wrong, reinitialize the connection */ gwlist_delete(p->pool, i, 1); dbpool_conn_destroy(pconn); p->curr_size--; reinit++; len--; i--; } else { n++; } } gwlist_unlock(p->pool); /* reinitialize brocken connections */ if (reinit > 0) n += dbpool_increase(p, reinit); return n; }
void alog(const char *fmt, ...) { char buf[FORMAT_SIZE + 1]; va_list args; if (file == NULL) return; format(buf, fmt); va_start(args, fmt); gwlist_lock(writers); gwlist_add_producer(writers); gwlist_unlock(writers); vfprintf(file, buf, args); fflush(file); gwlist_remove_producer(writers); va_end(args); }
void alog_reopen(void) { if (file == NULL) return; if (markers) alog("Log ends"); gwlist_lock(writers); /* wait for writers to complete */ gwlist_consume(writers); fclose(file); file = fopen(filename, "a"); gwlist_unlock(writers); if (file == NULL) { error(errno, "Couldn't re-open access logfile `%s'.", filename); } else if (markers) { alog("Log begins"); } }
/* * Set tid for an existing initiator. Input a cache item and the new tid. */ static void set_tid_by_item(WTPCached_tid *item, long tid) { gwlist_lock(tid_cache); item->tid = tid; gwlist_unlock(tid_cache); }
static Boxc *route_msg(List *route_info, Msg *msg) { AddrPar *ap; Boxc *conn, *best; int i, b, len; ap = gwlist_search(route_info, msg, cmp_route); if (ap == NULL) { debug("bb.boxc", 0, "Did not find previous routing info for WDP, " "generating new"); route: if (gwlist_len(wapbox_list) == 0) return NULL; gwlist_lock(wapbox_list); /* take random wapbox from list, and then check all wapboxes * and select the one with lowest load level - if tied, the first * one */ len = gwlist_len(wapbox_list); b = gw_rand() % len; best = gwlist_get(wapbox_list, b); for(i = 0; i < gwlist_len(wapbox_list); i++) { conn = gwlist_get(wapbox_list, (i+b) % len); if (conn != NULL && best != NULL) if (conn->load < best->load) best = conn; } if (best == NULL) { warning(0, "wapbox_list empty!"); gwlist_unlock(wapbox_list); return NULL; } conn = best; conn->load++; /* simulate new client until we get new values */ ap = gw_malloc(sizeof(AddrPar)); ap->address = octstr_duplicate(msg->wdp_datagram.source_address); ap->port = msg->wdp_datagram.source_port; ap->wapboxid = conn->id; gwlist_produce(route_info, ap); gwlist_unlock(wapbox_list); } else conn = gwlist_search(wapbox_list, ap, cmp_boxc); if (conn == NULL) { /* routing failed; wapbox has disappeared! * ..remove routing info and re-route */ debug("bb.boxc", 0, "Old wapbox has disappeared, re-routing"); gwlist_delete_equal(route_info, ap); ap_destroy(ap); goto route; } return conn; }
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; }