static void main_for_list_add_and_delete(void) { static char *items[] = { "one", "two", "three", }; int num_items = sizeof(items) / sizeof(items[0]); int num_repeats = 3; int i, j; char *p; List *list; list = gwlist_create(); for (j = 0; j < num_repeats; ++j) for (i = 0; i < num_items; ++i) gwlist_append(list, items[i]); gwlist_delete_matching(list, items[0], compare_cstr); for (i = 0; i < gwlist_len(list); ++i) { p = gwlist_get(list, i); if (strcmp(p, items[0]) == 0) panic(0, "list contains `%s' after deleting it!", items[0]); } for (i = 0; i < num_items; ++i) gwlist_delete_equal(list, items[i]); if (gwlist_len(list) != 0) panic(0, "list is not empty after deleting everything"); gwlist_destroy(list, NULL); }
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); }
/* * Go back and remove this timer's elapse event from the output list, * to pretend that it didn't elapse after all. This is necessary * to deal with some races between the timer thread and the caller's * start/stop actions. */ static void abort_elapsed(Timer *timer) { if (timer->elapsed_data == NULL) return; if (timer->output != NULL) gwlist_delete_equal(timer->output, timer->elapsed_data); timer->elapsed_data = NULL; }
static void push_client_machine_destroy(void *a) { WSPPushClientMachine *m; m = a; debug("wap.wsp", 0, "Destroying WSPPushClientMachine %p", (void *) m); gwlist_delete_equal(push_client_machines, m); #define INTEGER(name) m->name = 0; #define HTTPHEADERS(name) http_destroy_headers(m->name); #define MACHINE(fields) fields; #include "wsp_push_client_machine.def" gw_free(m); }
/* * Go back and remove this timer's elapse event from the output list, * to pretend that it didn't elapse after all. This is necessary * to deal with some races between the timer thread and the caller's * start/stop actions. */ static void abort_elapsed(Timer *timer) { long count; if (timer->elapsed_event == NULL) return; count = gwlist_delete_equal(timer->output, timer->elapsed_event); if (count > 0) { debug("timers", 0, "Aborting %s timer.", wap_event_name(timer->elapsed_event->type)); wap_event_destroy(timer->elapsed_event); } timer->elapsed_event = NULL; }
static void machine_destroy(void *pp) { WSPMachine *p; p = pp; debug("wap.wsp", 0, "Destroying WSPMachine %p", pp); gwlist_delete_equal(session_machines, p); #define INTEGER(name) p->name = 0; #define OCTSTR(name) octstr_destroy(p->name); #define HTTPHEADERS(name) http_destroy_headers(p->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name); #define MACHINESLIST(name) destroy_##name(p->name); #define CAPABILITIES(name) wsp_cap_destroy_list(p->name); #define COOKIES(name) cookies_destroy(p->name); #define REFERER(name) octstr_destroy(p->name); #define MACHINE(fields) fields #include "wsp_server_session_machine.def" gw_free(p); }
/* * Destroys a WTPInitMachine. Assumes it is safe to do so. Assumes it has * already been deleted from the machines list. */ static void init_machine_destroy(void *p) { WTPInitMachine *init_machine; init_machine = p; debug("wap.wtp", 0, "WTP: Destroying WTPInitMachine %p (%ld)", (void *) init_machine, init_machine->mid); gwlist_delete_equal(init_machines, init_machine); #define ENUM(name) init_machine->name = INITIATOR_NULL_STATE; #define INTEGER(name) init_machine->name = 0; #define EVENT(name) wap_event_destroy(init_machine->name); #define TIMER(name) gwtimer_destroy(init_machine->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(init_machine->name); #define MACHINE(field) field #include "wtp_init_machine.def" gw_free(init_machine); }
/* * Destroys a WTLSMachine. Assumes it is safe to do so. Assumes it has * already been deleted from the machines list. */ static void wtls_machine_destroy(void *p) { WTLSMachine *wtls_machine; wtls_machine = p; debug("wap.wtls", 0, "WTLS: Destroying WTLSMachine %ld (0x%p)", wtls_machine->mid, (void *)wtls_machine); gwlist_delete_equal(wtls_machines, wtls_machine); #define MACHINE(field) field #define ENUM(name) wtls_machine->name = NULL_STATE; #define ADDRTUPLE(name) wap_addr_tuple_destroy(wtls_machine->name); #define INTEGER(name) wtls_machine->name = 0; #define OCTSTR(name) octstr_destroy(wtls_machine->name); #define PDULIST(name) wtls_machine->name = NULL; #include "wtls_machine-decl.h" gw_free(wtls_machine); }
/* This function does NOT consume its event; it leaves that task up * to the parent session */ static void handle_method_event(WSPMachine *sm, WSPMethodMachine *msm, WAPEvent *current_event, WSP_PDU *pdu) { if (msm == NULL) { warning(0, "No method machine for event."); wap_event_dump(current_event); return; } debug("wap.wsp", 0, "WSP: method %ld, state %s, event %s", msm->transaction_id, state_name(msm->state), wap_event_name(current_event->type)); gw_assert(sm->session_id == msm->session_id); #define STATE_NAME(name) #define ROW(state_name, event, condition, action, next_state) \ { \ struct event *e; \ e = ¤t_event->u.event; \ if (msm->state == state_name && \ current_event->type == event && \ (condition)) { \ action \ msm->state = next_state; \ debug("wap.wsp", 0, "WSP %ld/%ld: New method state %s", \ msm->session_id, msm->transaction_id, #next_state); \ goto end; \ } \ } #include "wsp_server_method_states.def" cant_handle_event(sm, current_event); end: if (msm->state == NULL_METHOD) { method_machine_destroy(msm); gwlist_delete_equal(sm->methodmachines, msm); } }
static void handle_push_event(WSPMachine *sm, WSPPushMachine *pm, WAPEvent *current_event) { if (pm == NULL) { warning(0, "No push machine for event."); wap_event_dump(current_event); return; } debug("wap.wsp", 0, "WSP(tid/pid): push %ld/%ld, state %s, event %s", pm->transaction_id, pm->server_push_id, state_name(pm->state), wap_event_name(current_event->type)); gw_assert(sm->session_id == pm->session_id); #define STATE_NAME(name) #define ROW(state_name, event, condition, action, next_state) \ { \ if (pm->state == state_name && \ current_event->type == event && \ (condition)) { \ action \ pm->state = next_state; \ debug("wap.wsp", 0, "WSP %ld/%ld: New push state %s", \ pm->session_id, pm->transaction_id, #next_state); \ goto end; \ } \ } #include "wsp_server_push_states.def" cant_handle_event(sm, current_event); end: if (pm->state == SERVER_PUSH_NULL_STATE) { push_machine_destroy(pm); gwlist_delete_equal(sm->pushmachines, pm); } }
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; }
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); }