From 1a3aa4c9aa7f37dcc8b9dacdb5da79b5732d2c06 Mon Sep 17 00:00:00 2001 From: bagyenda <> Date: Tue, 2 Sep 2008 11:07:16 +0000 Subject: [PATCH] Added admin interface for mmsbox --- mbuni/ChangeLog | 2 + mbuni/mmlib/mms_cfg.def | 8 + mbuni/mmsbox/bearerbox.c | 45 +++- mbuni/mmsbox/mmsbox.c | 12 +- mbuni/mmsbox/mmsbox_cfg.c | 454 +++++++++++++++++++++++++++++++------- mbuni/mmsbox/mmsbox_cfg.h | 16 +- 6 files changed, 437 insertions(+), 100 deletions(-) diff --git a/mbuni/ChangeLog b/mbuni/ChangeLog index 3cc394c..aa3fe12 100644 --- a/mbuni/ChangeLog +++ b/mbuni/ChangeLog @@ -1,3 +1,5 @@ +2008-09-02 P. A. Bagyenda + * Added admin interface to mmsbox (can now start/stop and see status of any mmsc connection) 2008-09-01 P. A. Bagyenda * Rolled mmsrelay + mmsproxy into one item (for easier online management) 2008-08-29 P. A. Bagyenda diff --git a/mbuni/mmlib/mms_cfg.def b/mbuni/mmlib/mms_cfg.def index cc87bac..763b64b 100644 --- a/mbuni/mmlib/mms_cfg.def +++ b/mbuni/mmlib/mms_cfg.def @@ -100,6 +100,14 @@ SINGLE_GROUP(mbuni, OCTSTR(mmsbox-mt-filter-library) OCTSTR(mmsbox-mt-always-multipart) + + OCTSTR(mmsbox-admin-port) + OCTSTR(mmsc-admin-port) + OCTSTR(admin-port-ssl) + OCTSTR(admin-password) + + OCTSTR(admin-allow-ip) + OCTSTR(admin-deny-ip) ) MULTI_GROUP(mmsproxy, diff --git a/mbuni/mmsbox/bearerbox.c b/mbuni/mmsbox/bearerbox.c index aa30d9f..5507619 100644 --- a/mbuni/mmsbox/bearerbox.c +++ b/mbuni/mmsbox/bearerbox.c @@ -140,7 +140,7 @@ int mmsbox_send_report(Octstr *from, char *report_type, } /* These functions are very similar to those in mmsproxy */ -static void mm7soap_receive(MmsBoxHTTPClientInfo *h) +static int mm7soap_receive(MmsBoxHTTPClientInfo *h) { MSoapMsg_t *mreq = NULL, *mresp = NULL; @@ -167,6 +167,7 @@ static void mm7soap_receive(MmsBoxHTTPClientInfo *h) if (!mreq) { mresp = mm7_make_resp(NULL, MM7_SOAP_FORMAT_CORRUPT, NULL,1); + status = 4000; goto done; } @@ -315,6 +316,7 @@ static void mm7soap_receive(MmsBoxHTTPClientInfo *h) default: mresp = mm7_make_resp(mreq, MM7_SOAP_UNSUPPORTED_OPERATION, NULL,1); + status = MM7_SOAP_UNSUPPORTED_OPERATION; break; } @@ -342,9 +344,11 @@ static void mm7soap_receive(MmsBoxHTTPClientInfo *h) mm7_soap_destroy(mreq); gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); octstr_destroy(mmc_id); + + return MM7_SOAP_STATUS_OK(status) ? 0 : -1; } -static void mm7eaif_receive(MmsBoxHTTPClientInfo *h) +static int mm7eaif_receive(MmsBoxHTTPClientInfo *h) { MmsMsg *m = NULL; List *mh = NULL; @@ -547,7 +551,9 @@ static void mm7eaif_receive(MmsBoxHTTPClientInfo *h) octstr_destroy(mmc_id); http_destroy_headers(mh); - mms_destroy(m); + mms_destroy(m); + + return http_status_class(hstatus) == HTTP_STATUS_SUCCESSFUL ? 0 : -1; } @@ -557,6 +563,7 @@ static void dispatch_mm7_recv(List *rl) MmsBoxHTTPClientInfo *h; while ((h = gwlist_consume(rl)) != NULL) { + int ret = -1; MmscGrp *m = h->m; if (auth_check(m->incoming.user, m->incoming.pass, @@ -570,10 +577,16 @@ static void dispatch_mm7_recv(List *rl) info(0, "MMSBox: Auth failed, incoming connection, MMC group=[%s]", m->id ? octstr_get_cstr(m->id) : "(none)"); } else if (h->m->type == SOAP_MMSC) - mm7soap_receive(h); + ret = mm7soap_receive(h); else - mm7eaif_receive(h); + ret = mm7eaif_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); } } @@ -583,11 +596,12 @@ void mmsc_receive_func(MmscGrp *m) int i; MmsBoxHTTPClientInfo h = {NULL}; List *mmsc_incoming_reqs = gwlist_create(); + long *thids = gw_malloc((maxthreads + 1)*sizeof thids[0]); gwlist_add_producer(mmsc_incoming_reqs); for (i = 0; iid)); gwlist_remove_producer(mmsc_incoming_reqs); - gwthread_join_every((void *)dispatch_mm7_recv); - gwlist_destroy(mmsc_incoming_reqs, NULL); - debug("proxy", 0, "MMSBox: MM7 receiver Shutting down complete."); + for (i = 0; i= 0) + gwthread_join(thids[i]); + + gwlist_destroy(mmsc_incoming_reqs, NULL); + gw_free(thids); + + debug("proxy", 0, "MMSBox: MM7 receiver [mmc=%s] Shutting down complete.", octstr_get_cstr(m->id)); } @@ -984,7 +1003,11 @@ static int sendMsg(MmsEnvelope *e) e->hdrs, &new_msgid, &err); - + if (res == MMS_SEND_OK) + mmc->mt_pdus++; + else + mmc->mt_errors++; + mmc->last_pdu = time(NULL); return_mmsc_conn(mmc); /* important. */ done: if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) { diff --git a/mbuni/mmsbox/mmsbox.c b/mbuni/mmsbox/mmsbox.c index 05f1810..91355c0 100644 --- a/mbuni/mmsbox/mmsbox.c +++ b/mbuni/mmsbox/mmsbox.c @@ -574,7 +574,6 @@ int main(int argc, char *argv[]) { Octstr *fname; int cfidx; - mCfg *cfg; long qthread = 0, sthread = 0; @@ -588,11 +587,9 @@ int main(int argc, char *argv[]) fname = octstr_imm("mbuni.conf"); else fname = octstr_create(argv[cfidx]); - - cfg = mms_cfg_read(fname); - if (cfg == NULL) - panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname)); + if (mms_load_mmsbox_settings(fname,(gwthread_func_t *)mmsc_receive_func) < 0) + panic(0, "Configuration file loading failed, file: %s", octstr_get_cstr(fname)); octstr_destroy(fname); @@ -600,10 +597,6 @@ int main(int argc, char *argv[]) info(0, " " MM_NAME " MMSBox version %s starting", MMSC_VERSION); - mms_load_mmsbox_settings(cfg,(gwthread_func_t *)mmsc_receive_func); - - mms_cfg_destroy(cfg); - signal(SIGHUP, relog_now); signal(SIGTERM, quit_now); signal(SIGPIPE,SIG_IGN); /* Ignore pipe errors. They kill us sometimes for nothing*/ @@ -622,7 +615,6 @@ int main(int argc, char *argv[]) info(0, "Shutdown started.."); - mmsbox_cleanup_settings(); sleep(2); /* Wait for the sender thread, then quit. */ gwthread_join(qthread); /* Wait for it to die... */ diff --git a/mbuni/mmsbox/mmsbox_cfg.c b/mbuni/mmsbox/mmsbox_cfg.c index 63cf841..e18ff4d 100644 --- a/mbuni/mmsbox/mmsbox_cfg.c +++ b/mbuni/mmsbox/mmsbox_cfg.c @@ -43,30 +43,51 @@ MmsBoxResolverFuncStruct *rfs; /* resolver functions. */ void *rfs_data; Octstr *rfs_settings; - +static mCfg *cfg; /* Config. */ static Dict *mmscs = NULL; /* MMSC's indexed by ID. */ static List *mmsc_del_list = NULL; /* List of items to be deleted. */ - + +/* admin handler variables. */ +static long admin_port; +static long admin_thread = -1; +static Octstr *admin_pass = NULL; +static Octstr *admin_allow_ip = NULL; +static Octstr *admin_deny_ip = NULL; + +static gwthread_func_t *mmsc_receiver_func; + struct SendMmsPortInfo sendmms_port; struct MmsBoxMTfilter *mt_filter = NULL; static void free_mmsc_struct (MmscGrp *m); -static void mmsbox_start_mmsc_conn(MmscGrp *m, gwthread_func_t *mmsc_handler_func); -static void mmsbox_stop_mmsc_conn_real(MmscGrp *mmc); -int mms_load_mmsbox_settings(mCfg *cfg, gwthread_func_t *mmsc_handler_func) + +static void admin_handler(void *unused); + +int mms_load_mmsbox_settings(Octstr *fname, gwthread_func_t *mmsc_handler_func) { - mCfgGrp *grp = mms_cfg_get_single(cfg, octstr_imm("mbuni")); - mCfgGrp *cgrp = mms_cfg_get_single(cfg, octstr_imm("core")); + mCfgGrp *grp; + mCfgGrp *cgrp; Octstr *gdir = NULL, *s; - int send_port_ssl = 0; + int send_port_ssl = 0, admin_port_ssl = 0; List *l; int i, n, xx; void *catchall = NULL; - if (grp == NULL) - panic(0,"Missing required group `mbuni' in config file!"); + + if ((cfg = mms_cfg_read(fname)) == NULL) { + error(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname)); + return -1; + } + + grp = mms_cfg_get_single(cfg, octstr_imm("mbuni")); + cgrp = mms_cfg_get_single(cfg, octstr_imm("core")); + + if (grp == NULL) { + error(0,"Missing required group `mbuni' in config file!"); + return -1; + } mms_load_core_settings(cfg, cgrp); @@ -201,10 +222,29 @@ int mms_load_mmsbox_settings(mCfg *cfg, gwthread_func_t *mmsc_handler_func) } gwlist_destroy(l, NULL); - /* Get mmsc list. */ + mmsc_receiver_func = mmsc_handler_func; /* save it. */ + + /* Start MMSCs. */ l = mms_cfg_get_multi(cfg, octstr_imm("mmsc")); - for (i = 0, n = gwlist_len(l); i < n; i++) - start_mmsc_from_conf(cfg, gwlist_get(l, i), mmsc_handler_func); + for (i = 0, n = gwlist_len(l); i < n; i++) { + List *errors = gwlist_create(); + List *warnings = gwlist_create(); + Octstr *x; + + start_mmsc_from_conf(cfg, gwlist_get(l, i), mmsc_handler_func, errors, warnings); + + while ((x = gwlist_extract_first(errors)) != NULL) { + error(0, "%s", octstr_get_cstr(x)); + octstr_destroy(x); + } + + while ((x = gwlist_extract_first(warnings)) != NULL) { + warning(0, "%s", octstr_get_cstr(x)); + octstr_destroy(x); + } + gwlist_destroy(errors, NULL); + gwlist_destroy(warnings, NULL); + } gwlist_destroy(l, NULL); @@ -348,13 +388,37 @@ int mms_load_mmsbox_settings(mCfg *cfg, gwthread_func_t *mmsc_handler_func) gwlist_append(mms_services, m); } + + /* Finally load admin-port config and start the thingie */ + + mms_cfg_get_int(cfg, grp, octstr_imm("mmsbox-admin-port"), &admin_port); +#ifdef HAVE_LIBSSL + mms_cfg_get_bool(cfg, grp, octstr_imm("admin-port-ssl"), &admin_port_ssl); +#endif + admin_pass = mms_cfg_get(cfg, grp, octstr_imm("admin-password")); + + admin_allow_ip = mms_cfg_get(cfg, grp, octstr_imm("admin-allow-ip")); + admin_deny_ip = mms_cfg_get(cfg, grp, octstr_imm("admin-deny-ip")); + + if (admin_port > 0 && + http_open_port(admin_port, admin_port_ssl)< 0) + error(0, "Failed to start admin server on port %d: %s", + (int)admin_port, strerror(errno)); + else if (admin_port > 0 && + (admin_thread = gwthread_create((gwthread_func_t *)admin_handler, NULL)) < 0) { + error(0, "Failed to start admin server thread: %s", + strerror(errno)); + http_close_port(admin_port); + } else if (admin_pass == NULL) + warning(0, "Empty or no password supplied for admin port. All requests will be allowed!"); + gwlist_destroy(l, NULL); octstr_destroy(gdir); return 0; } -/* do nothing func. */ +/* do nothing func: Vital it returns 0! */ static int do_nothing_func (void) {return 0;} static MmsBoxMmscFuncs dummy_mmsc_funcs = { @@ -363,7 +427,62 @@ static MmsBoxMmscFuncs dummy_mmsc_funcs = { (void *)do_nothing_func }; -void start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_func) +#define ERROR(fmt,...) do {if (errors) gwlist_append(errors, octstr_format((fmt), ##__VA_ARGS__));} while(0) +#define WARNING(fmt,...) do {if (warnings) gwlist_append(warnings, octstr_format((fmt), ##__VA_ARGS__));}while(0) + + + +static void mmsbox_stop_mmsc_conn_real(MmscGrp *mmc) +{ + + if (mmc->type == CUSTOM_MMSC && mmc->fns + && mmc->custom_started) { + mmc->fns->stop_conn(mmc->data); + mmc->custom_started = 0; + } else if (mmc->incoming.port > 0) { + http_close_port(mmc->incoming.port); + if (mmc->threadid >= 0) + gwthread_join(mmc->threadid); + mmc->threadid = -1; + } + info(0, "Shutdown for mmsc [%s] complete", octstr_get_cstr(mmc->id)); +} + + +static void mmsbox_start_mmsc_conn(MmscGrp *m, gwthread_func_t *mmsc_handler_func, + List *errors, List *warnings) +{ + if (m->type == CUSTOM_MMSC) { + if (m->fns->start_conn(m, qfs, unified_prefix, strip_prefixes, &m->data) != 0) { + WARNING("MMSBox: Failed to start custom MMSC [%s]", octstr_get_cstr(m->id)); + m->custom_started = 0; + } else + m->custom_started = 1; + } else { + if (m->incoming.port > 0 && + http_open_port(m->incoming.port, m->incoming.ssl) < 0) { + WARNING("MMSBox: Failed to start HTTP server on receive port for " + " MMSC %s, port %ld: %s!", + octstr_get_cstr(m->id), m->incoming.port, + strerror(errno)); + m->incoming.port = 0; /* so we don't listen on it. */ + } + + if (mmsc_handler_func && m->incoming.port > 0) { /* Only start threads if func passed and ... */ + if ((m->threadid = gwthread_create(mmsc_handler_func, m)) < 0) + ERROR("MMSBox: Failed to start MMSC handler thread for MMSC[%s]: %s!", + octstr_get_cstr(m->id), strerror(errno)); + } else + m->threadid = -1; + } + + info(0, "Startup for mmsc [%s] complete", octstr_get_cstr(m->id)); +} + + + +MmscGrp *start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_func, + List *warnings, List *errors) { MmscGrp *m = gw_malloc(sizeof *m); @@ -373,14 +492,14 @@ void start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_f Octstr *s; memset(m, 0, sizeof *m); - + m->id = _mms_cfg_getx(cfg, x, octstr_imm("id")); if (octstr_len(m->id) < 1) { - error(0,"mmsbox.mmsc_config: Missing required field value `id' in config file!"); + ERROR("mmsbox.mmsc_config: Missing required field value `id' in config file!"); octstr_destroy(m->id); gw_free(m); - return; + return NULL; } m->group_id = mms_cfg_get(cfg, x, octstr_imm("group-id")); @@ -432,7 +551,7 @@ void start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_f m->fns = &dummy_mmsc_funcs; } } else - warning(0, "MMSBox: Unknown MMSC type [%s]!", + WARNING("MMSBox: Unknown MMSC type [%s]!", octstr_get_cstr(type)); if ((xver = _mms_cfg_getx(cfg, x, octstr_imm("mm7-version"))) != NULL && octstr_len(xver) > 0) @@ -468,11 +587,11 @@ void start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_f if (mt_filter) m->use_mt_filter = (mt_filter->init(m->mmsc_url, m->id, s) == 1); else - panic(0, "MMSBox: mt-filter-params set for MMSC[%s] but no MT-filter lib " + ERROR("MMSBox: mt-filter-params set for MMSC[%s] but no MT-filter lib " "specified!", octstr_get_cstr(m->id)); if (!m->use_mt_filter) - warning(0, "MMSBox: MT MMS filter turned off for MMSC[%s]. Init failed", + WARNING( "MMSBox: MT MMS filter turned off for MMSC[%s]. Init failed", octstr_get_cstr(m->id)); octstr_destroy(s); } else @@ -482,77 +601,38 @@ void start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_f mms_cfg_get_bool(cfg, x, octstr_imm("reroute-add-sender-to-subject"), &m->reroute_mod_subject); m->reroute_mmsc_id = mms_cfg_get(cfg, x, octstr_imm("reroute-mmsc-id")); if (m->reroute_mmsc_id != NULL && m->reroute == 0) - warning(0, "MMSBox: reroute-mmsc-id parameter set but reroute=false!"); + WARNING("MMSBox: reroute-mmsc-id parameter set but reroute=false!"); mms_cfg_get_bool(cfg, x, octstr_imm("no-sender-address"), &m->no_senderaddress); m->mutex = mutex_create(); m->incoming.ssl = ssl; - + m->start_time = time(NULL); + /* finally start the thingie. */ - mmsbox_start_mmsc_conn(m, mmsc_handler_func); + mmsbox_start_mmsc_conn(m, mmsc_handler_func, errors, warnings); if (dict_put_once(mmscs, m->id, m) == 0) { - error(0, "Failed to load mmsc <%s>. ID is not unique!", octstr_get_cstr(m->id)); + WARNING("Failed to load mmsc <%s>. ID is not unique!", octstr_get_cstr(m->id)); mmsbox_stop_mmsc_conn_real(m); free_mmsc_struct(m); - } -} - -static void mmsbox_start_mmsc_conn(MmscGrp *m, gwthread_func_t *mmsc_handler_func) -{ - if (m->type == CUSTOM_MMSC) { - if (m->fns->start_conn(m, qfs, unified_prefix, strip_prefixes, &m->data) != 0) { - warning(0, "MMSBox: Failed to start custom MMSC [%s]", octstr_get_cstr(m->id)); - m->custom_started = 0; - } else - m->custom_started = 1; - } else { - if (m->incoming.port > 0 && - http_open_port(m->incoming.port, m->incoming.ssl) < 0) { - warning(0, "MMSBox: Failed to start HTTP server on receive port for " - " MMSC %s, port %ld: %s!", - octstr_get_cstr(m->id), m->incoming.port, - strerror(errno)); - m->incoming.port = 0; /* so we don't listen on it. */ - } - - if (mmsc_handler_func && m->incoming.port > 0) { /* Only start threads if func passed and ... */ - if ((m->threadid = gwthread_create(mmsc_handler_func, m)) < 0) - error(0, "MMSBox: Failed to start MMSC handler thread for MMSC[%s]: %s!", - octstr_get_cstr(m->id), strerror(errno)); - } else - m->threadid = -1; + m = NULL; } - info(0, "Startup for mmsc [%s] complete", octstr_get_cstr(m->id)); + return m; } -static void mmsbox_stop_mmsc_conn_real(MmscGrp *mmc) -{ - - if (mmc->type == CUSTOM_MMSC && mmc->fns - && mmc->custom_started) { - mmc->fns->stop_conn(mmc->data); - mmc->custom_started = 0; - } else if (mmc->incoming.port > 0) { - http_close_port(mmc->incoming.port); - if (mmc->threadid >= 0) - gwthread_join(mmc->threadid); - mmc->threadid = -1; - } - info(0, "Shutdown for mmsc [%s] complete", octstr_get_cstr(mmc->id)); -} - -void mmsbox_stop_mmsc_conn(Octstr *mmc_id) +int mmsbox_stop_mmsc_conn(Octstr *mmc_id) { MmscGrp *mmc = dict_remove(mmscs, mmc_id); /* remove it so no one else can get it. */ if (mmc == NULL) - return; + return -1; mmsbox_stop_mmsc_conn_real(mmc); mmc->delete_after = time(NULL) + 5*60; /* delete after 5 minutes. */ gwlist_append(mmsc_del_list, mmc); /* to be deleted later. */ + + return 0; } void mmsbox_stop_all_mmsc_conn(void) @@ -663,6 +743,18 @@ void mmsbox_settings_cleanup(void) { delete_stale_mmsc(1); + /* eventually we will destroy the object. For now, we only cleanup queue module. */ + if (qfs) + qfs->mms_cleanup_queue_module(); + + if (admin_port > 0) { + http_close_port(admin_port); + gwthread_join(admin_thread); + info(0, "MmsBox: Admin port on %d, shutdown", (int)admin_port); + } + + + mms_cfg_destroy(cfg); /* only delete at end of session. */ /* More cleanups to follow. */ } @@ -736,11 +828,223 @@ Octstr *get_mmsbox_queue_dir(Octstr *from, List *to, MmscGrp *m, return 0; } -void mmsbox_cleanup_settings(void) +static void append_mmsc_status(Octstr *rbody, MmscGrp *m, List *warnings) { - /* eventually we will destroy the object. For now, we only cleanup queue module. */ - if (qfs) - qfs->mms_cleanup_queue_module(); + time_t t = time(NULL); + int i, n; + unsigned long tdiff; + char lbuf[128], ubuf[128], tmp[64], xport[32]; + + char *typ; + + if (m->type == SOAP_MMSC) + typ = "SOAP"; + else if (m->type == EAIF_MMSC) + typ = "EAIF"; + else if (m->type == CUSTOM_MMSC) + typ = "CUSTOM"; + else + typ = "none"; + + if (m->last_pdu > 0) { + struct tm tm = gw_localtime(m->last_pdu); + gw_strftime(lbuf,sizeof lbuf, "%x %X", &tm); + } else + strcpy(lbuf, "n/a"); + + /* Compute uptime */ + tdiff = t - m->start_time; + if (tdiff >= 24*3600) {/* we have some days */ + sprintf(ubuf, "%ld days", tdiff/(24*3600)); + + tdiff %= 24*3600; + } else + ubuf[0] = 0; + + if (tdiff >= 3600) { + long x = tdiff/3600; + sprintf(tmp, "%s%ld hrs", ubuf[0] ? " " : "", x); + strcat(ubuf, tmp); + tdiff %= 3600; + } + + if (tdiff >= 60) { + sprintf(tmp, "%s%ld mins", ubuf[0] ? " " : "", tdiff/60); + strcat(ubuf, tmp); + tdiff %= 60; + } + + if (tdiff > 0) { + sprintf(tmp, "%s%ld secs", ubuf[0] ? " " : "", tdiff); + strcat(ubuf, tmp); + } + + if (m->type != CUSTOM_MMSC) + sprintf(xport, "%d", (int)m->incoming.port); + else + sprintf(xport, "n/a"); + octstr_format_append(rbody, "\n " + "%s\n" + "%S\n" + "%.4f\n" + "%s\n" + "%S\n" + "\n" + "%s\n" + "%s\n" + "%ld%ld\n" + "%ld%ld\n" + "\n", + m->id, + typ, + xport, + m->group_id ? m->group_id : octstr_imm("n/a"), + m->throughput, + m->reroute ? "true" : "false", + m->reroute_mmsc_id ? m->reroute_mmsc_id : octstr_imm("N/A"), + ubuf, + lbuf, + (long)m->mt_pdus, (long)m->mt_errors, + (long)m->mo_pdus, (long)m->mo_errors); + + + for (i = 0, n = gwlist_len(warnings); i%S\n", gwlist_get(warnings, i)); + + octstr_append_cstr(rbody, "\n"); +} + +static void admin_handler(void *unused) +{ + HTTPClient *client; + Octstr *ip; + List *headers; + Octstr *url; + Octstr *body; + List *cgivars; + Octstr *pass; + Octstr *cmd; + + + info(0, "MmsBox: Admin Interface -- startup on port %d", (int)admin_port); + + while((client = http_accept_request(admin_port, + &ip, &url, &headers, + &body, &cgivars)) != NULL) { + int flg = -1; + Octstr *rbody = NULL; + int rstatus = HTTP_OK; + + if (!(flg = is_allowed_ip(admin_allow_ip, admin_deny_ip, ip)) || + ((pass = http_cgi_variable(cgivars, "password")) == NULL && admin_pass != NULL) || + (admin_pass && octstr_compare(pass, admin_pass) != 0)) { + error(0, "MmsBox: Improper access to mmsbox admin interface from IP[%s]: %s", + octstr_get_cstr(ip), + flg ? "Invalid/empty password" : "IP not allowed"); + if (flg) {/* means it is allowed by IP */ + rstatus = HTTP_UNAUTHORIZED; + rbody = octstr_imm("Auth failed"); + } + } else if ((cmd = http_cgi_variable(cgivars, "command")) == NULL) { + rbody = octstr_imm("Missing Command Parameter"); + rstatus = HTTP_BAD_REQUEST; + } else { + Octstr *mmc_id = http_cgi_variable(cgivars, "mmsc-id"); + List *l = NULL; + + rbody = octstr_create("\n"); + /* Command is one of: status, start, stop. + * mmsc-id is either empty (meaning ALL) or an ID of an existing MMSC connection. + */ + + if (octstr_str_case_compare(cmd, "start") == 0) { + mCfgGrp *m; + if (mmc_id == NULL) + l = mms_cfg_get_multi(cfg, octstr_imm("mmsc")); + else if ((m = mms_get_multi_by_field(cfg, + octstr_imm("mmsc"), + octstr_imm("id"), + mmc_id)) != NULL) { + l = gwlist_create(); + gwlist_append(l, m); + } + /* Start MMSCs. */ + + while ((m = gwlist_extract_first(l)) != NULL) { + List *e = gwlist_create(); + List *w = gwlist_create(); + Octstr *x; + MmscGrp *mc = start_mmsc_from_conf(cfg, m, mmsc_receiver_func, e, w); + + if (mc != NULL) + append_mmsc_status(rbody, mc, w); + else if (gwlist_len(e) > 0) + while ((x = gwlist_extract_first(e)) != NULL) { + octstr_format_append(rbody, + "%S\n", + x); + octstr_destroy(x); + } + gwlist_destroy(e, (void *)octstr_destroy); + gwlist_destroy(w, (void *)octstr_destroy); + + } + } else if (octstr_str_case_compare(cmd, "stop") == 0) { + Octstr *x; + if (mmc_id == NULL) + l = dict_keys(mmscs); + else { + l = gwlist_create(); + gwlist_append(l, octstr_duplicate(mmc_id)); + } + + while ((x = gwlist_extract_first(l)) != NULL) { + int ret = mmsbox_stop_mmsc_conn(x); + octstr_format_append(rbody, + "<%s/>\n", + ret == 0 ? "Success" : "Failed"); + octstr_destroy(x); + } + + } else if (octstr_str_case_compare(cmd, "status") == 0) { + Octstr *x; + MmscGrp *mc; + if (mmc_id == NULL) + l = dict_keys(mmscs); + else { + l = gwlist_create(); + gwlist_append(l, octstr_duplicate(mmc_id)); + } + + while ((x = gwlist_extract_first(l)) != NULL) { + if ((mc = dict_get(mmscs, x)) != NULL) + append_mmsc_status(rbody, mc, NULL); + octstr_destroy(x); + } + } + + gwlist_destroy(l, NULL); + } + + if (rbody) { + List *rh = http_create_empty_headers(); + http_header_add(rh, "Content-Type", "text/xml"); + http_send_reply(client, rstatus, rh, rbody); + + http_destroy_headers(rh); + + } else + http_close_client(client); + + octstr_destroy(rbody); + octstr_destroy(ip); + octstr_destroy(url); + octstr_destroy(body); + http_destroy_cgiargs(cgivars); + http_destroy_headers(headers); + } + + info(0, "MmsBox: Admin Interface -- shuttind down on port %d", (int)admin_port); } void free_mmsbox_http_clientInfo(MmsBoxHTTPClientInfo *h, int freeh) diff --git a/mbuni/mmsbox/mmsbox_cfg.h b/mbuni/mmsbox/mmsbox_cfg.h index 933060a..15de91b 100644 --- a/mbuni/mmsbox/mmsbox_cfg.h +++ b/mbuni/mmsbox/mmsbox_cfg.h @@ -49,6 +49,14 @@ typedef struct MmscGrp { void *data; /* data for above module. */ int custom_started; /* set to 1 if custom mmc started. */ + unsigned long mt_pdus; /* number of MT PDUs since start. */ + unsigned long mo_pdus; /* number of MO PDUs since start. */ + unsigned long mt_errors; /* number of MT errors since start */ + unsigned long mo_errors; /* number of MO errors since start */ + + time_t last_pdu; /* time of last PDU */ + time_t start_time; /* when was this connection started */ + int use_count; /* use counter. */ time_t delete_after; /* used to control deletion of object -- not ver clean, but... */ } MmscGrp; @@ -131,16 +139,16 @@ extern void *rfs_data; extern Octstr *rfs_settings; -extern int mms_load_mmsbox_settings(mCfg *cfg, gwthread_func_t *mmsc_handler_func); +extern int mms_load_mmsbox_settings(Octstr *fname, gwthread_func_t *mmsc_handler_func); extern void mmsbox_settings_cleanup(void); extern MmscGrp *get_handler_mmc(Octstr *id, Octstr *to, Octstr *from); extern void return_mmsc_conn(MmscGrp *m); extern Octstr *get_mmsbox_queue_dir(Octstr *from, List *to, MmscGrp *m, Octstr **mmc_id); -extern void mmsbox_cleanup_settings(void); -void start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_func); -void mmsbox_stop_mmsc_conn(Octstr *mmc); +MmscGrp *start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handler_func, + List *errors, List *warnings); +int mmsbox_stop_mmsc_conn(Octstr *mmc); void mmsbox_stop_all_mmsc_conn(void); typedef struct MmsBoxHTTPClientInfo { HTTPClient *client;