static void udp_sender(void *arg) { Msg *msg; Udpc *conn = arg; gwlist_add_producer(flow_threads); while(bb_status != BB_DEAD) { gwlist_consume(suspended); /* block here if suspended */ if ((msg = gwlist_consume(conn->outgoing_list)) == NULL) break; debug("bb.udp", 0, "udp: sending message"); if (send_udp(conn->fd, msg) == -1) /* ok, we failed... tough * XXX log the message or something like that... but this * is not as fatal as it is with SMS-messages... */ { msg_destroy(msg); continue; } counter_increase(outgoing_wdp_counter); msg_destroy(msg); } gwthread_join(conn->receiver); udpc_destroy(conn); gwlist_remove_producer(flow_threads); }
static void boxc_sender(void *arg) { Msg *msg; Boxc *conn = arg; gwlist_add_producer(flow_threads); while (bb_status != BB_DEAD && conn->alive) { /* * Make sure there's no data left in the outgoing connection before * doing the potentially blocking gwlist_consume()s */ conn_flush(conn->conn); gwlist_consume(suspended); /* block here if suspended */ if ((msg = gwlist_consume(conn->incoming)) == NULL) { /* tell sms/wapbox to die */ msg = msg_create(admin); msg->admin.command = restart ? cmd_restart : cmd_shutdown; send_msg(conn, msg); msg_destroy(msg); break; } if (msg_type(msg) == heartbeat) { debug("bb.boxc", 0, "boxc_sender: catch an heartbeat - we are alive"); msg_destroy(msg); continue; } boxc_sent_push(conn, msg); if (!conn->alive || send_msg(conn, msg) == -1) { /* we got message here */ boxc_sent_pop(conn, msg, NULL); gwlist_produce(conn->retry, msg); break; } msg_destroy(msg); debug("bb.boxc", 0, "boxc_sender: sent message to <%s>", octstr_get_cstr(conn->client_ip)); } /* the client closes the connection, after that die in receiver */ /* conn->alive = 0; */ /* set conn to unroutable */ conn->routable = 0; gwlist_remove_producer(flow_threads); }
/* * 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 void wtls_application(WAPEvent * event, WTLSMachine * wtls_machine) { int listLen, i = 0; WAPEvent *dgram; wtls_Payload *payLoad; /* Apply the negotiated decryption/decoding/MAC check to the received data */ /* Take the userdata and pass it on up to the WTP/WSP, depending on the destination port */ listLen = gwlist_len(event->u.T_Unitdata_Ind.pdu_list); for (; i < listLen; i++) { payLoad = gwlist_consume(event->u.T_Unitdata_Ind.pdu_list); dgram = wap_event_create(T_DUnitdata_Ind); dgram->u.T_DUnitdata_Ind.addr_tuple = wap_addr_tuple_create(event->u.T_Unitdata_Ind.addr_tuple-> remote->address, event->u.T_Unitdata_Ind.addr_tuple-> remote->port, event->u.T_Unitdata_Ind.addr_tuple-> local->address, event->u.T_Unitdata_Ind.addr_tuple-> local->port); dgram->u.T_DUnitdata_Ind.user_data = payLoad->data; wap_dispatch_datagram(dgram); payLoad->data = NULL; wtls_payload_destroy(payLoad); } }
static void wdp_router(void *arg) { Msg *msg; gwlist_add_producer(flow_threads); while (bb_status != BB_DEAD) { if ((msg = gwlist_consume(outgoing_wdp)) == NULL) break; gw_assert(msg_type(msg) == wdp_datagram); /* if (msg->list == sms) smsc_addwdp(msg); else */ udp_addwdp(msg); } udp_die(); /* smsc_endwdp(); */ gwlist_remove_producer(flow_threads); }
static void udp_sender(void *arg) { Msg *msg; Udpc *conn = arg; gwlist_add_producer(flow_threads); while (1) { if ((msg = gwlist_consume(conn->outgoing_list)) == NULL) break; info(0, "sending datagram <%s:%ld> -> <%s:%ld>", octstr_get_cstr(msg->wdp_datagram.source_address), msg->wdp_datagram.source_port, octstr_get_cstr(msg->wdp_datagram.destination_address), msg->wdp_datagram.destination_port); dump(msg); if (send_udp(conn->fd, msg) == -1) { msg_destroy(msg); continue; } counter_increase(outgoing_wdp_counter); msg_destroy(msg); } gwthread_join(conn->receiver); udpc_destroy(conn); gwlist_remove_producer(flow_threads); }
static void main_thread(void *arg) { WAPEvent *e; WSPMachine *sm; WSP_PDU *pdu; while (run_status == running && (e = gwlist_consume(queue)) != NULL) { wap_event_assert(e); switch (e->type) { case TR_Invoke_Ind: pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data); if (pdu == NULL) { warning(0, "WSP: Broken PDU ignored."); wap_event_destroy(e); continue; } break; default: pdu = NULL; break; } sm = find_session_machine(e, pdu); if (sm == NULL) { wap_event_destroy(e); } else { handle_session_event(sm, e, pdu); } wsp_pdu_destroy(pdu); } }
static void main_thread(void *arg) { WAPEvent *e; while (run_status == running && (e = gwlist_consume(ota_queue)) != NULL) { handle_ota_event(e); } }
void semaphore_down(Semaphore *semaphore) { gw_assert(semaphore != NULL); #ifdef HAVE_SEMAPHORE sem_wait(&semaphore->sem); #else gwlist_consume(semaphore->list); #endif }
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); }
static void consumer(void *arg) { List *list; Item *item; list = arg; for (;;) { item = gwlist_consume(list); if (item == NULL) break; received[item->index] = 1; gw_free(item); } }
static void main_thread(void *arg) { WTLSMachine *sm; WAPEvent *e; while (wtls_run_status == running && (e = gwlist_consume(wtls_queue))) { sm = wtls_machine_find_or_create(e); if (sm == NULL) wap_event_destroy(e); else wtls_event_handle(sm, e); } }
static void main_thread(void *arg) { WTPInitMachine *sm; WAPEvent *e; while (initiator_run_status == running && (e = gwlist_consume(queue)) != NULL) { sm = init_machine_find_or_create(e); if (sm == NULL) wap_event_destroy(e); else handle_init_event(sm, e); } }
static void main_thread(void *arg) { WSPPushClientMachine *cpm; WAPEvent *e; while (push_client_run_status == running && (e = gwlist_consume(push_client_queue)) != NULL) { cpm = push_client_machine_find_or_create(e); if (cpm == NULL) wap_event_destroy(e); else push_client_event_handle(cpm, e); } }
static void tdeliver(struct Qthread_t *qt) { MmsEnvelope *e; struct qfile_t *qfs; while ((e = gwlist_consume(qt->l)) != NULL) { int res; /* qt->deliver(e) will attempt to deliver the message, but it may not be delivered * to all recipients (because of errors). If it is delivered or a fatal error * occurs, then the queue is deleted by qt->deliver (and e is deallocated) */ res = qt->deliver(e); debug("", 0, "qt->deliver terminates: %d", res); switch(res) { case -1: // FATAL ERROR if (e == NULL) { error(0, "tdeliver: An non-recoverable error occured - but the envelope was deallocated so I cannot give you any details."); } else { qfs = e->qfs_data; char fname[2*QFNAMEMAX]; snprintf(fname, -1 + sizeof fname, "%s/%s%s", qfs->dir, qfs->subdir, qfs->name); error(0, "tdeliver: An non-recoverable error occured - Check (and delete) queue file %s", fname); free_envelope(e, 0); // Should we automatically delete file?? } break; case 0: // Delete queue entry from memory only free_envelope(e, 0); break; case 1: // Queue entry gone anywhow.. break; default: /* Never happens, but log an error if it does */ error(0, "qt->deliver returned a strange value (%d) that I can't handle!", res); break; } debug("",0,"free envelope stuff cleared here."); // Are we absolutely sure the file has been closed here??? // Yes! } /* Consume failed, time to go away. */ if (qt->l) gwlist_destroy(qt->l, NULL); qt->l = NULL; /* Signal that we are gone. */ }
static void sql_list(Boxc *boxc) { Msg *msg; List *qlist, *save_list; qlist = gwlist_create(); gwlist_add_producer(qlist); save_list = gwlist_create(); gwlist_add_producer(save_list); while (sqlbox_status == SQL_RUNNING && boxc->alive) { if ( gw_sql_fetch_msg_list(qlist, limit_per_cycle) > 0 ) { while((gwlist_len(qlist)>0) && ((msg = gwlist_consume(qlist)) != NULL )) { if (charset_processing(msg) == -1) { error(0, "Could not charset process message, dropping it!"); msg_destroy(msg); continue; } if (global_sender != NULL && (msg->sms.sender == NULL || octstr_len(msg->sms.sender) == 0)) { msg->sms.sender = octstr_duplicate(global_sender); } /* convert validity and deferred to unix timestamp */ if (msg->sms.validity != SMS_PARAM_UNDEFINED) msg->sms.validity = time(NULL) + msg->sms.validity * 60; if (msg->sms.deferred != SMS_PARAM_UNDEFINED) msg->sms.deferred = time(NULL) + msg->sms.deferred * 60; send_msg(boxc->bearerbox_connection, boxc, msg); /* convert validity & deferred back to minutes */ if (save_mt && msg->sms.validity != SMS_PARAM_UNDEFINED) msg->sms.validity = (msg->sms.validity - time(NULL))/60; if (save_mt && msg->sms.deferred != SMS_PARAM_UNDEFINED) msg->sms.deferred = (msg->sms.deferred - time(NULL))/60; gwlist_produce(save_list, msg); } /* save_list also deletes and destroys messages */ gw_sql_save_list(save_list, octstr_imm("MT"), save_mt); } else { gwthread_sleep(SLEEP_BETWEEN_EMPTY_SELECTS); } } gwlist_remove_producer(qlist); gwlist_remove_producer(save_list); gwlist_destroy(qlist, msg_destroy_item); gwlist_destroy(save_list, msg_destroy_item); }
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; } }
static unsigned long run_batch(void) { Octstr *no; unsigned long linerr = 0; unsigned long lineno = 0; while ((no = gwlist_consume(lines)) != NULL) { if (octstr_check_range(no, 0, 256, gw_isdigit)) { Msg *msg; lineno++; msg = msg_create(sms); msg->sms.smsc_id = smsc_id ? octstr_duplicate(smsc_id) : NULL; msg->sms.service = service ? octstr_duplicate(service) : NULL; msg->sms.sms_type = mt_push; msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(no); msg->sms.account = account ? octstr_duplicate(account) : NULL; msg->sms.msgdata = content ? octstr_duplicate(content) : octstr_create(""); msg->sms.dlr_mask = dlr_mask; msg->sms.dlr_url = octstr_duplicate(dlr_url); msg->sms.udhdata = octstr_create(""); msg->sms.coding = DC_7BIT; if (send_message(msg) < 0) { linerr++; info(0,"Failed to send message at line <%ld> for receiver `%s' to bearerbox.", lineno, octstr_get_cstr(no)); msg_destroy(msg); } } else { linerr++; error(0, "Receiver `%s' at line <%ld> contains non-digit characters, discarded!", octstr_get_cstr(no), lineno); } octstr_destroy(no); } info(0,"mtbatch has processed %ld messages with %ld errors.", lineno, linerr); return lineno; }
static void service_router(void *arg) { Msg *msg; gwlist_add_producer(flow_threads); while (1) { if ((msg = gwlist_consume(incoming_wdp)) == NULL) break; gw_assert(msg_type(msg) == wdp_datagram); udp_addwdp_from_client(msg); } udp_die(); gwlist_remove_producer(flow_threads); }
static int udp_die(void) { Udpc *udpc; if (!udp_running) return -1; /* * remove producers from all outgoing lists. */ debug("bb.udp", 0, "udp_die: removing producers from udp-lists"); while ((udpc = gwlist_consume(udpc_list)) != NULL) { gwlist_remove_producer(udpc->outgoing_list); } gwlist_destroy(udpc_list, NULL); udp_running = 0; return 0; }
int gw_rwlock_wrlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_wrlock(&lock->rwlock); if (ret != 0) panic(ret, "Error while pthread_rwlock_wrlock."); #else RWDEBUG("", 0, "------------ gw_rwlock_wrlock(%p) ----------", lock); gwlist_lock(lock->rwlock); RWDEBUG("", 0, "------------ gw_rwlock_wrlock(%p) producers=%d", lock, gwlist_producer_count(lock->rwlock)); /* wait for reader */ gwlist_consume(lock->rwlock); lock->writer = gwthread_self(); #endif return ret; }
static void wrapper_receiver(void *arg) { Msg *msg; SMSCConn *conn = arg; SmscWrapper *wrap = conn->data; /* SmscWrapper *wrap = conn->data; ** non-used */ double sleep = 0.0001; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* remove messages from SMSC until we are killed */ while(conn->why_killed == SMSCCONN_ALIVE) { gwlist_consume(wrap->stopped); /* block here if suspended/isolated */ msg = sms_receive(conn); if (msg) { debug("bb.sms", 0, "smscconn (%s): new message received", octstr_get_cstr(conn->name)); sleep = 0.0001; bb_smscconn_receive(conn, msg); } else { /* note that this implementations means that we sleep even * when we fail connection.. but time is very short, anyway */ gwthread_sleep(sleep); /* gradually sleep longer and longer times until something starts to * happen - this of course reduces response time, but that's better than * extensive CPU usage when it is not used */ sleep *= 2; if (sleep >= 2.0) sleep = 1.999999; } } conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; /* this thread is joined at sender */ }
void wtp_pdu_destroy(WTP_PDU *pdu) { if (pdu == NULL) return; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: {\ struct name *p; p = &pdu->u.name; \ fields \ } break; #define UINT(field, docstring, bits) #define UINTVAR(field, docstring) #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field); #define REST(field, docstring) octstr_destroy(p->field); #define TYPE(bits, value) #define RESERVED(bits) #define TPI(confield) #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type); break; } if (pdu->options) { while (gwlist_len(pdu->options)) { wtp_tpi_destroy(gwlist_consume(pdu->options)); } gwlist_destroy(pdu->options, NULL); } gw_free(pdu); }
static void wapboxc_run(void *arg) { int fd, port; gwlist_add_producer(flow_threads); gwthread_wakeup(MAIN_THREAD_ID); port = (int) *((long*)arg); fd = make_server_socket(port, NULL); /* XXX add interface_name if required */ if (fd < 0) { panic(0, "Could not open wapbox port %d", port); } wait_for_connections(fd, run_wapbox, incoming_wdp, wapbox_port_ssl); /* continue avalanche */ gwlist_remove_producer(outgoing_wdp); /* wait for all connections to die and then remove list */ while(gwlist_wait_until_nonempty(wapbox_list) == 1) gwthread_sleep(1.0); /* wait for wdp_to_wapboxes to exit */ while(gwlist_consume(wapbox_list)!=NULL) ; /* close listen socket */ close(fd); gwlist_destroy(wapbox_list, NULL); wapbox_list = NULL; gwlist_remove_producer(flow_threads); }
static void wait_for_connections(int fd, void (*function) (void *arg), List *waited, int ssl) { int ret; int timeout = 10; /* 10 sec. */ gw_assert(function != NULL); while(bb_status != BB_DEAD) { /* if we are being shutdowned, as long as there is * messages in incoming list allow new connections, but when * list is empty, exit. * Note: We have timeout (defined above) for which we allow new connections. * Otherwise we wait here for ever! */ if (bb_status == BB_SHUTDOWN) { ret = gwlist_wait_until_nonempty(waited); if (ret == -1 || !timeout) break; else timeout--; } /* block here if suspended */ gwlist_consume(suspended); ret = gwthread_pollfd(fd, POLLIN, 1.0); if (ret > 0) { Boxc *newconn = accept_boxc(fd, ssl); if (newconn != NULL) { gwthread_create(function, newconn); gwthread_sleep(1.0); } else { error(0, "Failed to create new boxc connection."); } } else if (ret < 0 && errno != EINTR && errno != EAGAIN) error(errno, "bb_boxc::wait_for_connections failed"); } }
static void dispatch_mm7_recv(List *rl) { MmsBoxHTTPClientInfo *h; while ((h = gwlist_consume(rl)) != NULL) { int ret = -1, has_auth = 0; MmscGrp *m = h->m; if (auth_check(m->incoming.user, m->incoming.pass, h->headers, &has_auth) != 0) { /* Ask it to authenticate... */ List *hh = http_create_empty_headers(); http_header_add(hh, "WWW-Authenticate", "Basic realm=\"" MM_NAME "\""); http_send_reply(h->client, HTTP_UNAUTHORIZED, hh, octstr_imm("Authentication failed")); http_destroy_headers(hh); if (!has_auth) mms_info_ex("auth",0, "MM7", m->id, "Auth failed, incoming connection, MMC group=[%s]", m->id ? octstr_get_cstr(m->id) : "(none)"); else mms_error_ex("auth",0, "MM7", m->id, "Auth failed, incoming connection, MMC group=[%s]", m->id ? octstr_get_cstr(m->id) : "(none)"); } else if (h->m->type == SOAP_MMSC) ret = mm7soap_receive(h); else if (h->m->type == EAIF_MMSC) ret = mm7eaif_receive(h); else ret = mm7http_receive(h); h->m->last_pdu = time(NULL); if (ret == 0) h->m->mo_pdus++; else h->m->mo_errors++; free_mmsbox_http_clientInfo(h, 1); } }
static int store_file_save(Msg *msg) { if (filename == NULL) return 0; /* block here until store not loaded */ gwlist_consume(loaded); /* lock file_mutex in order to have dict and file in sync */ mutex_lock(file_mutex); if (store_to_dict(msg) == -1) { mutex_unlock(file_mutex); return -1; } /* write to file, too */ write_msg(msg); fflush(file); mutex_unlock(file_mutex); return 0; }
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"); } }
/* * Thread to send queued messages */ static void httpsmsc_sender(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; Msg *msg; double delay = 0; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); if (conn->throughput) { delay = 1.0 / conn->throughput; } while (conndata->shutdown == 0) { /* check if we can send ; otherwise block on semaphore */ if (conndata->max_pending_sends) semaphore_down(conndata->max_pending_sends); if (conndata->shutdown) { if (conndata->max_pending_sends) semaphore_up(conndata->max_pending_sends); break; } msg = gwlist_consume(conndata->msg_to_send); if (msg == NULL) break; /* obey throughput speed limit, if any */ if (conn->throughput > 0) { gwthread_sleep(delay); } counter_increase(conndata->open_sends); if (conndata->callbacks->send_sms(conn, msg) == -1) { counter_decrease(conndata->open_sends); if (conndata->max_pending_sends) semaphore_up(conndata->max_pending_sends); } } /* put outstanding sends back into global queue */ while((msg = gwlist_extract_first(conndata->msg_to_send))) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); /* if there no receiver shutdown */ if (conndata->port <= 0) { /* unblock http_receive_result() if there are no open sends */ if (counter_value(conndata->open_sends) == 0) http_caller_signal_shutdown(conndata->http_ref); if (conndata->send_cb_thread != -1) { gwthread_wakeup(conndata->send_cb_thread); gwthread_join(conndata->send_cb_thread); } mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; mutex_unlock(conn->flow_mutex); if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL) conndata->callbacks->destroy(conn); conn->data = NULL; conndata_destroy(conndata); bb_smscconn_killed(); } }
static void wrapper_sender(void *arg) { Msg *msg; SMSCConn *conn = arg; SmscWrapper *wrap = conn->data; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* send messages to SMSC until our outgoing_list is empty and * no producer anymore (we are set to shutdown) */ while(conn->status != SMSCCONN_DEAD) { if ((msg = gwlist_consume(wrap->outgoing_queue)) == NULL) break; if (octstr_search_char(msg->sms.receiver, ' ', 0) != -1) { /* * multi-send: this should be implemented in corresponding * SMSC protocol, but while we are waiting for that... */ int i; Msg *newmsg; /* split from spaces: in future, split with something more sensible, * this is dangerous... (as space is url-encoded as '+') */ List *nlist = octstr_split_words(msg->sms.receiver); debug("bb.sms", 0, "Handling multi-receiver message"); for(i=0; i < gwlist_len(nlist); i++) { newmsg = msg_duplicate(msg); octstr_destroy(newmsg->sms.receiver); newmsg->sms.receiver = gwlist_get(nlist, i); sms_send(conn, newmsg); } gwlist_destroy(nlist, NULL); msg_destroy(msg); } else sms_send(conn,msg); } /* cleanup, we are now dying */ debug("bb.sms", 0, "SMSCConn %s sender died, waiting for receiver", octstr_get_cstr(conn->name)); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; if (conn->is_stopped) { gwlist_remove_producer(wrap->stopped); conn->is_stopped = 0; } gwthread_wakeup(wrap->receiver_thread); gwthread_join(wrap->receiver_thread); /* call 'failed' to all messages still in queue */ mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; while((msg = gwlist_extract_first(wrap->outgoing_queue))!=NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } smscwrapper_destroy(wrap); conn->data = NULL; mutex_unlock(conn->flow_mutex); bb_smscconn_killed(); }