static Connection *cgw_open_send_connection(SMSCConn *conn) { PrivData *privdata = conn->data; int wait; Connection *server; Msg *msg; wait = 0; while (!privdata->shutdown) { /* Change status only if the first attempt to form a * connection fails, as it's possible that the SMSC closed the * connection because of idle timeout and a new one will be * created quickly. */ if (wait) { if (conn->status == SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); } while ((msg = gwlist_extract_first(privdata->outgoing_queue))) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); info(0, "smsc_cgw: waiting for %d minutes before trying to connect again", wait); gwthread_sleep(wait * 60); wait = wait > 5 ? 10 : wait * 2; } else wait = 1; server = conn_open_tcp_with_port(privdata->host, privdata->port, privdata->our_port, conn->our_host); if (privdata->shutdown) { conn_destroy(server); return NULL; } if (server == NULL) { error(0, "smsc_cgw: opening TCP connection to %s failed", octstr_get_cstr(privdata->host)); continue; } if (conn->status != SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); } return server; } return NULL; }
static int reconnect(SMSCConn *conn) { SmscWrapper *wrap = conn->data; Msg *msg; int ret; int wait = 1; /* disable double-reconnect * NOTE: it is still possible that we do double-connect if * first thread gets through this if-statement and then * execution switches to another thread.. this can be avoided * via double-mutex system, but I do not feel it is worth it, * maybe later --rpr */ if (conn->status == SMSCCONN_RECONNECTING) { mutex_lock(wrap->reconnect_mutex); /* wait here */ mutex_unlock(wrap->reconnect_mutex); return 0; } mutex_lock(wrap->reconnect_mutex); debug("bb.sms", 0, "smsc_wrapper <%s>: reconnect started", octstr_get_cstr(conn->name)); while((msg = gwlist_extract_first(wrap->outgoing_queue))!=NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); } conn->status = SMSCCONN_RECONNECTING; while(conn->why_killed == SMSCCONN_ALIVE) { ret = smsc_reopen(wrap->smsc); if (ret == 0) { info(0, "Re-open of %s succeeded.", octstr_get_cstr(conn->name)); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); break; } else if (ret == -2) { error(0, "Re-open of %s failed permanently", octstr_get_cstr(conn->name)); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(wrap->reconnect_mutex); mutex_unlock(conn->flow_mutex); return -1; /* permanent failure */ } else { error(0, "Re-open to <%s> failed, retrying after %d minutes...", octstr_get_cstr(conn->name), wait); gwthread_sleep(wait*60.0); wait = wait > 10 ? 10 : wait * 2 + 1; } } mutex_unlock(wrap->reconnect_mutex); return 0; }
/* * Thread to handle finished sendings */ static void httpsmsc_send_cb(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; Msg *msg; int status; List *headers; Octstr *final_url, *body; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while(conndata->shutdown == 0 || counter_value(conndata->open_sends)) { msg = http_receive_result(conndata->http_ref, &status, &final_url, &headers, &body); if (msg == NULL) break; /* they told us to die, by unlocking */ counter_decrease(conndata->open_sends); if (conndata->max_pending_sends) semaphore_up(conndata->max_pending_sends); /* Handle various states here. */ /* request failed and we are not in shutdown mode */ if (status == -1 && conndata->shutdown == 0) { error(0, "HTTP[%s]: Couldn't connect to SMS center." "(retrying in %ld seconds) %ld.", octstr_get_cstr(conn->id), conn->reconnect_delay, counter_value(conndata->open_sends)); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); /* XXX how should we know whether it's temp. error ?? */ bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); /* * Just sleep reconnect delay and set conn to ACTIVE again; * otherwise if no pending request are here, we leave conn in * RECONNECTING state for ever and no routing (trials) take place. */ if (counter_value(conndata->open_sends) == 0) { gwthread_sleep(conn->reconnect_delay); /* and now enable routing again */ mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; time(&conn->connect_time); mutex_unlock(conn->flow_mutex); /* tell bearerbox core that we are connected again */ bb_smscconn_connected(conn); } continue; } /* request failed and we *are* in shutdown mode, drop the message */ else if (status == -1 && conndata->shutdown == 1) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } /* request succeeded */ else { /* we received a response, so this link is considered online again */ if (conn->status != SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; time(&conn->connect_time); mutex_unlock(conn->flow_mutex); /* tell bearerbox core that we are connected again */ bb_smscconn_connected(conn); } conndata->callbacks->parse_reply(conn, msg, status, headers, body); } http_destroy_headers(headers); octstr_destroy(final_url); octstr_destroy(body); } debug("smsc.http", 0, "HTTP[%s]: httpsmsc_send_cb dying", octstr_get_cstr(conn->id)); conndata->shutdown = 1; if (counter_value(conndata->open_sends)) { warning(0, "HTTP[%s]: Shutdown while <%ld> requests are pending.", octstr_get_cstr(conn->id), counter_value(conndata->open_sends)); } }
static void cgw_sender(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; Msg *msg = NULL; Connection *server = NULL; int l = 0; int ret = 0; conn->status = SMSCCONN_CONNECTING; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (!privdata->shutdown) { /* check that connection is active */ if (conn->status != SMSCCONN_ACTIVE) { if ((server = cgw_open_send_connection(conn)) == NULL) { privdata->shutdown = 1; error(0, "Unable to connect to CGW server"); return ; } conn->status = SMSCCONN_ACTIVE; bb_smscconn_connected(conn); } else { ret = 0; l = gwlist_len(privdata->outgoing_queue); if (l > 0) ret = cgw_send_loop(conn, server); /* send any messages in queue */ if (ret != -1) ret = cgw_wait_command(privdata, conn, server, 1); /* read ack's and delivery reports */ if (ret != -1) cgw_check_acks(privdata); /* check un-acked messages */ if (ret == -1) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); } } } conn_destroy(server); while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; gwlist_destroy(privdata->outgoing_queue, NULL); octstr_destroy(privdata->host); octstr_destroy(privdata->allow_ip); octstr_destroy(privdata->deny_ip); gw_free(privdata); conn->data = NULL; mutex_unlock(conn->flow_mutex); debug("bb.sms", 0, "smsc_cgw connection has completed shutdown."); bb_smscconn_killed(); }
static void fake_listener(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; struct sockaddr_in client_addr; socklen_t client_addr_len; Octstr *ip; Connection *client; int s, ret; Msg *msg; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (1) { client_addr_len = sizeof(client_addr); ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1); if (ret == -1) { if (errno == EINTR) continue; error(0, "Poll for fakesmsc connections failed, shutting down"); break; } if (privdata->shutdown) break; if (ret == 0) /* * This thread was woke up from elsewhere, but * if we're not shutting down nothing to do here. */ continue; s = accept(privdata->listening_socket, (struct sockaddr *)&client_addr, &client_addr_len); if (s == -1) { warning(errno, "fake_listener: accept() failed, retrying..."); continue; } ip = host_ip(client_addr); if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) { info(0, "Fakesmsc connection tried from denied host <%s>, " "disconnected", octstr_get_cstr(ip)); octstr_destroy(ip); close(s); continue; } client = conn_wrap_fd(s, 0); if (client == NULL) { error(0, "fake_listener: conn_wrap_fd failed on accept()ed fd"); octstr_destroy(ip); close(s); continue; } conn_claim(client); info(0, "Fakesmsc client connected from %s", octstr_get_cstr(ip)); octstr_destroy(ip); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); main_connection_loop(conn, client); if (privdata->shutdown) break; mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); } } if (close(privdata->listening_socket) == -1) warning(errno, "smsc_fake: couldn't close listening socket at shutdown"); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } gwlist_destroy(privdata->outgoing_queue, NULL); octstr_destroy(privdata->allow_ip); octstr_destroy(privdata->deny_ip); gw_free(privdata); conn->data = NULL; mutex_unlock(conn->flow_mutex); debug("bb.sms", 0, "smsc_fake connection has completed shutdown."); bb_smscconn_killed(); }