From 5afec26e5d0327a28dedcca0eea89c3b3e4d977b Mon Sep 17 00:00:00 2001 From: bagyenda <> Date: Mon, 8 Sep 2008 11:50:24 +0000 Subject: [PATCH] mmsc admin interface --- mbuni/ChangeLog | 3 + mbuni/mmlib/mms_cfg.def | 3 +- mbuni/mmlib/mms_util.h | 3 + mbuni/mmsbox/bearerbox.c | 38 ++- mbuni/mmsbox/mmsbox.c | 6 +- mbuni/mmsbox/mmsbox_cfg.c | 82 +++-- mbuni/mmsc/mmsc.c | 13 +- mbuni/mmsc/mmsc_cfg.c | 568 +++++++++++++++++++++++++++++------ mbuni/mmsc/mmsc_cfg.h | 32 +- mbuni/mmsc/mmsfromemail.c | 19 +- mbuni/mmsc/mmsglobalsender.c | 89 ++++-- mbuni/mmsc/mmsproxy.c | 72 +++-- mbuni/mmsc/mmssend.c | 17 +- 13 files changed, 712 insertions(+), 233 deletions(-) diff --git a/mbuni/ChangeLog b/mbuni/ChangeLog index 8f61609..3d283f4 100644 --- a/mbuni/ChangeLog +++ b/mbuni/ChangeLog @@ -1,3 +1,6 @@ +2008-09-08 P. A. Bagyenda + * MMSC admin interface added (start/stop/status of each VASP connection) + * MMSC VASP can now have multiple short codes 2008-09-04 P. A. Bagyenda * Minor fix/addition for Content-ID handling * Generalised event logger module (to facilitate alarms, etc) diff --git a/mbuni/mmlib/mms_cfg.def b/mbuni/mmlib/mms_cfg.def index 08f3e3b..df7cb16 100644 --- a/mbuni/mmlib/mms_cfg.def +++ b/mbuni/mmlib/mms_cfg.def @@ -131,13 +131,14 @@ MULTI_GROUP(mms-vasp, OCTSTR(mm7-soap-xmlns) OCTSTR(use-mm7-soap-namespace-prefix) OCTSTR(short-code) + OCTSTR(short-codes) OCTSTR(vasp-username) OCTSTR(vasp-password) OCTSTR(vasp-url) OCTSTR(mms-to-email-handler) OCTSTR(mms-to-local-copy-handler) OCTSTR(send-uaprof) - + OCTSTR(throughput) ) MULTI_GROUP(send-mms-user, diff --git a/mbuni/mmlib/mms_util.h b/mbuni/mmlib/mms_util.h index 673118d..f5a2109 100644 --- a/mbuni/mmlib/mms_util.h +++ b/mbuni/mmlib/mms_util.h @@ -40,6 +40,9 @@ #define MMS_SEND_ERROR_TRANSIENT -1 #define MMS_SEND_ERROR_FATAL -2 +/* Aging of old (internal) records... */ +#define DEFAULT_DELETE_AGE 10*60 + #define SEND_ERROR_STR(e) ((e) == MMS_SEND_OK ? "Sent" : \ (e) == MMS_SEND_ERROR_TRANSIENT ? "Retry later" : \ ((e) == MMS_SEND_QUEUED ? "Queued" : "Failed")) diff --git a/mbuni/mmsbox/bearerbox.c b/mbuni/mmsbox/bearerbox.c index 33b5b04..45fb4cf 100644 --- a/mbuni/mmsbox/bearerbox.c +++ b/mbuni/mmsbox/bearerbox.c @@ -42,14 +42,14 @@ -static int auth_check(Octstr *user, Octstr *pass, List *headers) +static int auth_check(Octstr *user, Octstr *pass, List *headers, int *has_auth_hdr) { int i, res = -1; Octstr *v = http_header_value(headers, octstr_imm("Authorization")); Octstr *p = NULL, *q = NULL; - if (user == NULL || - octstr_len(user) == 0) { + *has_auth_hdr = (v != NULL); + if (octstr_len(user) == 0) { res = 0; goto done; } @@ -563,19 +563,23 @@ static void dispatch_mm7_recv(List *rl) MmsBoxHTTPClientInfo *h; while ((h = gwlist_consume(rl)) != NULL) { - int ret = -1; + int ret = -1, has_auth = 0; MmscGrp *m = h->m; if (auth_check(m->incoming.user, m->incoming.pass, - h->headers) != 0) { /* Ask it to authenticate... */ + 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); - mms_info(0, "MM7", m->id, "Auth failed, incoming connection, MMC group=[%s]", - m->id ? octstr_get_cstr(m->id) : "(none)"); + 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 @@ -632,7 +636,7 @@ void mmsc_receive_func(MmscGrp *m) } else { h.ua = http_header_value(h.headers, octstr_imm("User-Agent")); - mms_error(0, "MM7", m->id, "HTTP: Incoming IP denied MMSC[%s] ip=[%s], ua=[%s], disconnected", + mms_error_ex("auth",0, "MM7", m->id, "HTTP: Incoming IP denied MMSC[%s] ip=[%s], ua=[%s], disconnected", m->id ? octstr_get_cstr(m->id) : "(none)", h.ip ? octstr_get_cstr(h.ip) : "(none)", h.ua ? octstr_get_cstr(h.ua) : "(none)"); @@ -894,7 +898,7 @@ static int mms_sendtommsc(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *transi from, to, transid, linkedid, vasid, service_code, m, hdrs, err, &retry); else - mms_error(0, "MM7", mmc->id, "MMC[%s] of unknown type, can't send!", + mms_error_ex("MT", 0, "MM7", mmc->id, "MMC[%s] of unknown type, can't send!", mmc->id ? octstr_get_cstr(mmc->id) : ""); throughput = mmc->throughput; @@ -1023,11 +1027,17 @@ static int sendMsg(MmsEnvelope *e) if (res == MMS_SEND_ERROR_FATAL) to->process = 0; /* No more attempts. */ - mms_info(0, "MM7", NULL, "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: msgid=[%s], err=%s", - SEND_ERROR_STR(res), - octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, - new_msgid ? octstr_get_cstr(new_msgid) : NULL, - err ? octstr_get_cstr(err) : "(none)"); + if (err == NULL) + mms_info(0, "MM7", NULL, "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: msgid=[%s]", + SEND_ERROR_STR(res), + octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, + new_msgid ? octstr_get_cstr(new_msgid) : NULL); + else + mms_error_ex("MT", 0, + "MM7", NULL, + "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld", + SEND_ERROR_STR(res), + octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize); octstr_destroy(new_msgid); octstr_destroy(err); diff --git a/mbuni/mmsbox/mmsbox.c b/mbuni/mmsbox/mmsbox.c index 5eb9dbf..ae4dc76 100644 --- a/mbuni/mmsbox/mmsbox.c +++ b/mbuni/mmsbox/mmsbox.c @@ -1201,7 +1201,8 @@ static void dispatch_sendmms_recv(List *rl) Octstr *password; Octstr *err = NULL; List *cgivar_ctypes = NULL; - + char *etype = NULL; + int res = 0, tparse = parse_cgivars(h->headers, h->body, &h->cgivars, &cgivar_ctypes); username = http_cgi_variable(h->cgivars, "username"); @@ -1380,10 +1381,11 @@ static void dispatch_sendmms_recv(List *rl) "username=%s, password=%s!", username ? octstr_get_cstr(username) : "(null)", password ? octstr_get_cstr(password) : "(null)"); + etype = "auth"; } if (err && res != 0) - mms_error(0, "mmsbox", NULL, "%s", octstr_get_cstr(err)); + mms_error_ex(etype, 0, "mmsbox", NULL, "%s", octstr_get_cstr(err)); octstr_destroy(err); /* Free the ip and other stuff here. */ diff --git a/mbuni/mmsbox/mmsbox_cfg.c b/mbuni/mmsbox/mmsbox_cfg.c index a710383..b5a1240 100644 --- a/mbuni/mmsbox/mmsbox_cfg.c +++ b/mbuni/mmsbox/mmsbox_cfg.c @@ -628,6 +628,26 @@ MmscGrp *start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, gwthread_func_t *mmsc_handl return m; } +static void delete_stale_mmsc(int delete_all) +{ + MmscGrp *mmc; + int n = gwlist_len(mmsc_del_list); + + while (n-- > 0 && + (mmc = gwlist_extract_first(mmsc_del_list)) != NULL) + if (delete_all || + (mmc->use_count <= 0 && + mmc->delete_after <= time(NULL))) + free_mmsc_struct(mmc); + else + gwlist_append(mmsc_del_list, mmc); /* put it back. */ + + if (delete_all) { + gwlist_destroy(mmsc_del_list, NULL); + mmsc_del_list = NULL; + } +} + int mmsbox_stop_mmsc_conn(Octstr *mmc_id) { MmscGrp *mmc = dict_remove(mmscs, mmc_id); /* remove it so no one else can get it. */ @@ -637,9 +657,10 @@ int mmsbox_stop_mmsc_conn(Octstr *mmc_id) mmsbox_stop_mmsc_conn_real(mmc); - mmc->delete_after = time(NULL) + 5*60; /* delete after 5 minutes. */ + mmc->delete_after = time(NULL) + DEFAULT_DELETE_AGE; /* delete after X minutes. */ gwlist_append(mmsc_del_list, mmc); /* to be deleted later. */ + delete_stale_mmsc(0); /* Also delete stale ones on each stop. */ return 0; } @@ -727,25 +748,6 @@ done: } -static void delete_stale_mmsc(int delete_all) -{ - MmscGrp *mmc; - int n = gwlist_len(mmsc_del_list); - - while (n-- > 0 && - (mmc = gwlist_extract_first(mmsc_del_list)) != NULL) - if (delete_all || - (mmc->use_count <= 0 && - mmc->delete_after <= time(NULL))) - free_mmsc_struct(mmc); - else - gwlist_append(mmsc_del_list, mmc); /* put it back. */ - - if (delete_all) { - gwlist_destroy(mmsc_del_list, NULL); - mmsc_del_list = NULL; - } -} void mmsbox_settings_cleanup(void) { @@ -891,18 +893,18 @@ static void append_mmsc_status(Octstr *rbody, MmscGrp *m, List *warnings) 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", + 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, @@ -917,9 +919,9 @@ static void append_mmsc_status(Octstr *rbody, MmscGrp *m, List *warnings) for (i = 0, n = gwlist_len(warnings); i%S\n", gwlist_get(warnings, i)); + octstr_format_append(rbody, "%S\n", gwlist_get(warnings, i)); - octstr_append_cstr(rbody, "\n"); + octstr_append_cstr(rbody, "\n"); } static void admin_handler(void *unused) @@ -931,7 +933,6 @@ static void admin_handler(void *unused) Octstr *body; List *cgivars; Octstr *pass; - Octstr *cmd; mms_info(0, "mmsbox", NULL,"Admin Interface -- startup on port %d", (int)admin_port); @@ -953,19 +954,16 @@ static void admin_handler(void *unused) 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. + /* URI 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) { + if (octstr_str_case_compare(url, "/start") == 0) { mCfgGrp *m; if (mmc_id == NULL) l = mms_cfg_get_multi(cfg, octstr_imm("mmsc")); @@ -997,7 +995,7 @@ static void admin_handler(void *unused) gwlist_destroy(w, (void *)octstr_destroy); } - } else if (octstr_str_case_compare(cmd, "stop") == 0) { + } else if (octstr_str_case_compare(url, "/stop") == 0) { Octstr *x; if (mmc_id == NULL) l = dict_keys(mmscs); @@ -1014,7 +1012,7 @@ static void admin_handler(void *unused) octstr_destroy(x); } - } else if (octstr_str_case_compare(cmd, "status") == 0) { + } else if (octstr_str_case_compare(url, "/status") == 0) { Octstr *x; MmscGrp *mc; if (mmc_id == NULL) diff --git a/mbuni/mmsc/mmsc.c b/mbuni/mmsc/mmsc.c index 4164480..0785b46 100644 --- a/mbuni/mmsc/mmsc.c +++ b/mbuni/mmsc/mmsc.c @@ -14,11 +14,9 @@ #include "mmsc.h" #include "mms_uaprof.h" -static mCfg *cfg; MmscSettings *settings; List *proxyrelays; - static void quit_now(int notused) { stop_mmsrelay(); @@ -51,21 +49,14 @@ int main(int argc, char *argv[]) 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)); - - octstr_destroy(fname); mms_info(0, "mmsc", NULL, "----------------------------------------"); mms_info(0, "mmsc", NULL," " MM_NAME " MMSC version %s starting", MMSC_VERSION); - settings = mms_load_mmsc_settings(cfg,&proxyrelays); + settings = mms_load_mmsc_settings(fname,&proxyrelays); - mms_cfg_destroy(cfg); - + octstr_destroy(fname); if (!settings) panic(0, "No MMSC configuration!"); diff --git a/mbuni/mmsc/mmsc_cfg.c b/mbuni/mmsc/mmsc_cfg.c index a124824..6a4d9c2 100644 --- a/mbuni/mmsc/mmsc_cfg.c +++ b/mbuni/mmsc/mmsc_cfg.c @@ -26,35 +26,61 @@ #define MMS_PORT 8191 /* Default content fetch port. */ +static void free_vasp(MmsVasp *m); - +static void delete_stale_vasps(MmscSettings *settings, int delete_all); +static void admin_handler(MmscSettings *settings); void mms_cleanup_mmsc_settings(MmscSettings *settings) { - /* eventually we will destroy the object. For now, we only cleanup queue module. */ - settings->qfs->mms_cleanup_queue_module(); + /* eventually we will destroy the object. */ + if (settings->admin_port > 0) { + http_close_port(settings->admin_port); + + if (settings->admin_thread >= 0) + gwthread_join(settings->admin_thread); + + mms_info(0, "mmsc", NULL,"Admin port on %d, shutdown", (int)settings->admin_port); + } + + settings->qfs->mms_cleanup_queue_module(); + delete_stale_vasps(settings, 1); mms_event_logger_cleanup(); } -MmscSettings *mms_load_mmsc_settings(mCfg *cfg, List **proxyrelays) +MmscSettings *mms_load_mmsc_settings(Octstr *fname, List **proxyrelays) { + mCfg *cfg; Octstr *s; - List *l; - mCfgGrp *grp = mms_cfg_get_single(cfg, octstr_imm("mbuni")); - mCfgGrp *cgrp = mms_cfg_get_single(cfg, octstr_imm("core")); - MmscSettings *m = gw_malloc(sizeof *m); + mCfgGrp *grp; + mCfgGrp *cgrp; + MmscSettings *m; long port = -1; Octstr *from, *user, *pass; Octstr *qdir = NULL; - int i, n, xx = 0; + int i, n, xx = 0, ssl = 0; void *x; + + cfg = mms_cfg_read(fname); + + if (cfg == NULL) + panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname)); + + + cgrp = mms_cfg_get_single(cfg, octstr_imm("core")); + grp = mms_cfg_get_single(cfg, octstr_imm("mbuni")); + + m = gw_malloc(sizeof *m); memset(m, 0, sizeof *m); if (grp == NULL) panic(0,"Missing required group `mbuni' in config file!"); + m->cfg = cfg; /* store it since admin thread needs it. */ + m->vasp_del_list = gwlist_create(); + mms_load_core_settings(cfg, cgrp); if ((x = _mms_load_module(cfg, grp, "event-logger-module", "event_logger", NULL)) != NULL) { @@ -278,91 +304,208 @@ MmscSettings *mms_load_mmsc_settings(mCfg *cfg, List **proxyrelays) /* Now load the VASP list. */ l = mms_cfg_get_multi(cfg, octstr_imm("mms-vasp")); - m->vasp_list = gwlist_create(); - for (i=0, n=gwlist_len(l); iid = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-id")); - mv->short_code = -1; - mms_cfg_get_int(cfg, grp, octstr_imm("short-code"), &mv->short_code); + m->vasp_list = dict_create(53, NULL); + for (i=0, n=gwlist_len(l); ivasp_username = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-username")); - mv->vasp_password = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-password")); - - mv->vasp_url = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-url")); - - s = _mms_cfg_getx(cfg, grp, octstr_imm("type")); + mmsc_load_vasp_from_conf(m, gwlist_get(l, i), e, w); - if (octstr_case_compare(s, octstr_imm("soap")) == 0) - mv->type = SOAP_VASP; - else if (octstr_case_compare(s, octstr_imm("eaif")) == 0) - mv->type = EAIF_VASP; - else - mv->type = NONE_VASP; - octstr_destroy(s); - - mv->ver.major = mv->ver.minor1 = mv->ver.minor2 = 0; - if ((s = mms_cfg_get(cfg, grp, octstr_imm("mm7-version"))) != NULL && - octstr_len(s) > 0) - sscanf(octstr_get_cstr(s), "%d.%d.%d", &mv->ver.major, &mv->ver.minor1, &mv->ver.minor2); - else { - if (mv->type == SOAP_VASP) { - mv->ver.major = MAJOR_VERSION(DEFAULT_MM7_VERSION); - mv->ver.minor1 = MINOR1_VERSION(DEFAULT_MM7_VERSION); - mv->ver.minor2 = MINOR2_VERSION(DEFAULT_MM7_VERSION); - } else if (mv->type == EAIF_VASP) { - mv->ver.major = 3; - mv->ver.minor1 = 0; - } + while ((x = gwlist_extract_first(e)) != NULL) { + mms_error(0, "mmsc", NULL, "%s", octstr_get_cstr(x)); + octstr_destroy(x); } - octstr_destroy(s); - - if ((s = mms_cfg_get(cfg, grp, octstr_imm("mm7-soap-xmlns"))) != NULL) { - strncpy(mv->ver.xmlns, octstr_get_cstr(s), sizeof mv->ver.xmlns); - mv->ver.xmlns[-1 + sizeof mv->ver.xmlns] = 0; /* NULL terminate, just in case. */ - octstr_destroy(s); - } else - mv->ver.xmlns[0] = 0; - - mv->ver.use_mm7_namespace = 1; - mms_cfg_get_bool(cfg, grp, octstr_imm("use-mm7-soap-namespace-prefix"), &mv->ver.use_mm7_namespace); - - /* Set the handler vasp accounts. */ - if (mms_cfg_get_bool(cfg, grp, octstr_imm("mms-to-email-handler"), &ibool) == 0 && - ibool) { - if (m->mms2email) - mms_warning(0, "mmsc", NULL,"mms-to-email handler VASP specified more than once! Only last config taken."); - m->mms2email = mv; - } - if (mms_cfg_get_bool(cfg, grp, octstr_imm("mms-to-local-copy-handler"), &ibool) == 0 && - ibool) { - if (m->mms2mobile) - mms_warning(0, "mmsc", NULL,"mms-to-mobile copy handler VASP specified more than once! Only last config taken."); - m->mms2mobile = mv; + while ((x = gwlist_extract_first(w)) != NULL) { + mms_warning(0, "mmsc", NULL, "%s", octstr_get_cstr(x)); + octstr_destroy(x); } - - if ((s = mms_cfg_get(cfg, grp, octstr_imm("send-uaprof"))) != NULL){ - if (octstr_str_case_compare(s, "url") == 0) - mv->send_uaprof = UAProf_URL; - else if (octstr_str_case_compare(s, "ua") == 0) - mv->send_uaprof = UAProf_UA; - else { - mms_warning(0, "mmsc", NULL,"unknown send-uaprof value '%s'. Must be \"ua\" or \"url\"!", - octstr_get_cstr(s)); - mv->send_uaprof = UAProf_None; - } - octstr_destroy(s); - } - gwlist_append(m->vasp_list, mv); + gwlist_destroy(e, NULL); + gwlist_destroy(w, NULL); } gwlist_destroy(l, NULL); + + /* Now load & start admin interface. */ + + mms_cfg_get_int(cfg, grp, octstr_imm("mmsc-admin-port"), &m->admin_port); +#ifdef HAVE_LIBSSL + mms_cfg_get_bool(cfg, grp, octstr_imm("admin-port-ssl"), &ssl); +#endif + m->admin_pass = mms_cfg_get(cfg, grp, octstr_imm("admin-password")); + + m->admin_allow_ip = mms_cfg_get(cfg, grp, octstr_imm("admin-allow-ip")); + m->admin_deny_ip = mms_cfg_get(cfg, grp, octstr_imm("admin-deny-ip")); + + if (m->admin_port > 0 && + http_open_port(m->admin_port, ssl)< 0) { + mms_error(0, "mmsc", NULL, "Failed to start admin server on port %d: %s", + (int)m->admin_port, strerror(errno)); + m->admin_port = -1; + } else if (m->admin_port > 0 && + (m->admin_thread = gwthread_create((gwthread_func_t *)admin_handler, m)) < 0) { + mms_error(0, "mmsc", NULL, "Failed to start admin server thread: %s", + strerror(errno)); + http_close_port(m->admin_port); + m->admin_port = -1; + } else if (m->admin_pass == NULL) + mms_warning(0, "mmsc", NULL, "Empty or no password supplied for admin port. All requests will be allowed!"); + return m; } +int mmsc_unload_vasp(MmscSettings *m, Octstr *id) +{ + + MmsVasp *mv = dict_remove(m->vasp_list, id); + + if (mv == NULL) + return -1; + + if (m->mms2email == mv) + m->mms2email = NULL; + + if (m->mms2mobile == mv) + m->mms2mobile = NULL; + + mv->delete_after = time(NULL) + DEFAULT_DELETE_AGE; + gwlist_append(m->vasp_del_list, mv); + + delete_stale_vasps(m, 0); + return 0; +} + +#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) + +MmsVasp *mmsc_load_vasp_from_conf(MmscSettings *m, mCfgGrp *grp, List *errors, List *warnings) +{ + mCfg *cfg = m->cfg; + MmsVasp *mv = gw_malloc(sizeof *mv), *ret = NULL; + Octstr *s; + int ibool = 0; + long short_code; + + memset(mv, 0, sizeof mv[0]); + + mv->throughput = -1; + mv->num_short_codes = 0; + + mv->id = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-id")); + + if (mms_cfg_get_int(cfg, grp, octstr_imm("short-code"), &short_code) == 0) { + WARNING("'short-code' is deprecated, please use 'short-codes'"); + mv->num_short_codes = 1; + mv->short_codes = gw_malloc(sizeof mv->short_codes[0]); + mv->short_codes[0] = short_code; + } else if ((s = mms_cfg_get(cfg, grp, octstr_imm("short-codes"))) != NULL) { + List *l = octstr_split(s, octstr_imm(";")); + Octstr *x; + mv->short_codes = gw_malloc((gwlist_len(l) + 1) * sizeof mv->short_codes[0]); + + while ((x = gwlist_extract_first(l)) != NULL) { + if ((short_code = strtoul(octstr_get_cstr(x), NULL, 10)) == 0 && + (errno == EINVAL || errno == ERANGE)) + ERROR("Invalid short-code format: %S", x); + else + mv->short_codes[mv->num_short_codes++] = short_code; + octstr_destroy(x); + } + gwlist_destroy(l, NULL); + octstr_destroy(s); + } + + if (mv->num_short_codes == 0) { + ERROR("No valid short codes defined, VASP cannot be loaded"); + free_vasp(mv); + goto done; + } + + if ((s = mms_cfg_get(cfg, grp, octstr_imm("throughput"))) != NULL) { + mv->throughput = atof(octstr_get_cstr(s)); + octstr_destroy(s); + } + + mv->vasp_username = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-username")); + mv->vasp_password = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-password")); + + mv->vasp_url = _mms_cfg_getx(cfg, grp, octstr_imm("vasp-url")); + + s = _mms_cfg_getx(cfg, grp, octstr_imm("type")); + + if (octstr_case_compare(s, octstr_imm("soap")) == 0) + mv->type = SOAP_VASP; + else if (octstr_case_compare(s, octstr_imm("eaif")) == 0) + mv->type = EAIF_VASP; + else + mv->type = NONE_VASP; + octstr_destroy(s); + + mv->ver.major = mv->ver.minor1 = mv->ver.minor2 = 0; + if ((s = mms_cfg_get(cfg, grp, octstr_imm("mm7-version"))) != NULL && + octstr_len(s) > 0) + sscanf(octstr_get_cstr(s), "%d.%d.%d", &mv->ver.major, &mv->ver.minor1, &mv->ver.minor2); + else { + if (mv->type == SOAP_VASP) { + mv->ver.major = MAJOR_VERSION(DEFAULT_MM7_VERSION); + mv->ver.minor1 = MINOR1_VERSION(DEFAULT_MM7_VERSION); + mv->ver.minor2 = MINOR2_VERSION(DEFAULT_MM7_VERSION); + } else if (mv->type == EAIF_VASP) { + mv->ver.major = 3; + mv->ver.minor1 = 0; + } + } + octstr_destroy(s); + + if ((s = mms_cfg_get(cfg, grp, octstr_imm("mm7-soap-xmlns"))) != NULL) { + strncpy(mv->ver.xmlns, octstr_get_cstr(s), sizeof mv->ver.xmlns); + + mv->ver.xmlns[-1 + sizeof mv->ver.xmlns] = 0; /* NULL terminate, just in case. */ + octstr_destroy(s); + } else + mv->ver.xmlns[0] = 0; + + mv->ver.use_mm7_namespace = 1; + mms_cfg_get_bool(cfg, grp, octstr_imm("use-mm7-soap-namespace-prefix"), &mv->ver.use_mm7_namespace); + + /* Set the handler vasp accounts. */ + if (mms_cfg_get_bool(cfg, grp, octstr_imm("mms-to-email-handler"), &ibool) == 0 && + ibool) { + if (m->mms2email) + WARNING("mms-to-email handler VASP res-et!."); + m->mms2email = mv; + } + if (mms_cfg_get_bool(cfg, grp, octstr_imm("mms-to-local-copy-handler"), &ibool) == 0 && + ibool) { + if (m->mms2mobile) + WARNING("mms-to-mobile copy handler VASP re-set."); + m->mms2mobile = mv; + } + + if ((s = mms_cfg_get(cfg, grp, octstr_imm("send-uaprof"))) != NULL){ + if (octstr_str_case_compare(s, "url") == 0) + mv->send_uaprof = UAProf_URL; + else if (octstr_str_case_compare(s, "ua") == 0) + mv->send_uaprof = UAProf_UA; + else { + WARNING("unknown send-uaprof value '%s'. Must be \"ua\" or \"url\"!", + octstr_get_cstr(s)); + mv->send_uaprof = UAProf_None; + } + octstr_destroy(s); + } + mv->stats.start_time = time(NULL); + + if (dict_put_once(m->vasp_list, mv->id, mv) == 0) { + ERROR("Failed to load vasp <%S>. ID is not unique!", mv->id); + free_vasp(mv); + } else + ret = mv; + +done: + return ret; +} + List *mms_proxy_relays(mCfg *cfg, Octstr *myhostname) { List *gl = mms_cfg_get_multi(cfg, octstr_imm("mmsproxy")); @@ -622,3 +765,260 @@ void notify_prov_server(char *cmd, char *from, char *event, char *arg, Octstr *m octstr_destroy(tmp3); octstr_destroy(tmp4); } + +static void free_vasp(MmsVasp *m) +{ + if (m == NULL) + return; + octstr_destroy(m->id); + octstr_destroy(m->vasp_username); + octstr_destroy(m->vasp_password); + octstr_destroy(m->vasp_url); + + if (m->short_codes) + gw_free(m->short_codes); + + gw_free(m); +} + +static void delete_stale_vasps(MmscSettings *settings, int delete_all) +{ + MmsVasp *mv; + int n = gwlist_len(settings->vasp_del_list); + + while (n-- > 0 && + (mv = gwlist_extract_first(settings->vasp_del_list)) != NULL) + if (delete_all || + mv->delete_after <= time(NULL)) + free_vasp(mv); + else + gwlist_append(settings->vasp_del_list, mv); /* put it back. */ + + if (delete_all) { + gwlist_destroy(settings->vasp_del_list, NULL); + settings->vasp_del_list = NULL; + } +} + + +static void append_vasp_status(Octstr *rbody, MmsVasp *m, List *warnings) +{ + time_t t = time(NULL); + int i, n; + unsigned long tdiff; + char lbuf[128], ubuf[128], tmp[64], mm7ver[64] = "n/a"; + + char *typ; + + + if (m->type == SOAP_VASP) { + typ = "SOAP"; + sprintf(mm7ver, "%d.%d.%d", m->ver.major, m->ver.minor1, m->ver.minor2); + } else if (m->type == EAIF_VASP) { + typ = "EAIF"; + sprintf(mm7ver, EAIF_VERSION, m->ver.major, m->ver.minor1); + } else + typ = "none"; + + if (m->stats.last_pdu > 0) { + struct tm tm = gw_localtime(m->stats.last_pdu); + gw_strftime(lbuf,sizeof lbuf, "%x %X", &tm); + } else + strcpy(lbuf, "n/a"); + + /* Compute uptime */ + tdiff = t - m->stats.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->throughput > 0) + sprintf(tmp, "%.2f", m->throughput); + else + sprintf(tmp, "n/a"); + octstr_format_append(rbody, "\n " + "%S\n" + "%S\n" + "%s\n" + "%s\n" + "%s\n" + "\n" + "%s\n" + "%s\n" + "%ld%ld\n" + "%ld%ld\n" + "\n" + "\n" , + m->id, + typ, + m->vasp_url, + m->vasp_username, + tmp, + mm7ver, + m->send_uaprof == UAProf_URL ? + "url" : (m->send_uaprof == UAProf_UA ? "user-agent" : "n/a"), + ubuf, + lbuf, + (long)m->stats.mt_pdus, (long)m->stats.mt_errors, + (long)m->stats.mo_pdus, (long)m->stats.mo_errors); + + + for (i = 0; inum_short_codes; i++) + octstr_format_append(rbody, "%ld\n", m->short_codes[i]); + + octstr_append_cstr(rbody, "\n"); + + for (i = 0, n = gwlist_len(warnings); i%S\n", gwlist_get(warnings, i)); + + octstr_append_cstr(rbody, "\n"); +} + +static void admin_handler(MmscSettings *settings) +{ + + HTTPClient *client; + Octstr *ip; + List *headers; + Octstr *url; + Octstr *body; + List *cgivars; + Octstr *pass; + + mms_info(0, "mmsc", NULL,"Admin Interface -- startup on port %d", (int)settings->admin_port); + + while((client = http_accept_request(settings->admin_port, + &ip, &url, &headers, + &body, &cgivars)) != NULL) { + int flg = -1; + Octstr *rbody = NULL; + int rstatus = HTTP_OK; + + if (!(flg = is_allowed_ip(settings->admin_allow_ip, settings->admin_deny_ip, ip)) || + ((pass = http_cgi_variable(cgivars, "password")) == NULL && + settings->admin_pass != NULL) || + (settings->admin_pass && octstr_compare(pass, settings->admin_pass) != 0)) { + mms_error(0, "mmsc", NULL, "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 { + Octstr *vasp_id = http_cgi_variable(cgivars, "vasp-id"); + List *l = NULL; + + rbody = octstr_create("\n"); + /* Command URI is one of: /status, /start, /stop. + * vasp-id is either empty (meaning ALL) or an ID of an existing VASPs connection. + */ + + if (octstr_str_case_compare(url, "/start") == 0) { + mCfgGrp *m; + if (vasp_id == NULL) + l = mms_cfg_get_multi(settings->cfg, octstr_imm("mms-vasp")); + else if ((m = mms_get_multi_by_field(settings->cfg, + octstr_imm("mms-vasp"), + octstr_imm("vasp-id"), + vasp_id)) != NULL) { + l = gwlist_create(); + gwlist_append(l, m); + } + /* Start MMS VASPs. */ + + while ((m = gwlist_extract_first(l)) != NULL) { + Octstr *x; + List *e = gwlist_create(); + List *w = gwlist_create(); + MmsVasp *mv = mmsc_load_vasp_from_conf(settings, m, e, w); + + if (mv != NULL) + append_vasp_status(rbody, mv, 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(url, "/stop") == 0) { + Octstr *x; + if (vasp_id == NULL) + l = dict_keys(settings->vasp_list); + else { + l = gwlist_create(); + gwlist_append(l, octstr_duplicate(vasp_id)); + } + + while ((x = gwlist_extract_first(l)) != NULL) { + int ret = mmsc_unload_vasp(settings, x); + octstr_format_append(rbody, + "<%s/>\n", + ret == 0 ? "Success" : "Failed"); + octstr_destroy(x); + } + } else if (octstr_str_case_compare(url, "/status") == 0) { + Octstr *x; + MmsVasp *mv; + if (vasp_id == NULL) + l = dict_keys(settings->vasp_list); + else { + l = gwlist_create(); + gwlist_append(l, octstr_duplicate(vasp_id)); + } + + while ((x = gwlist_extract_first(l)) != NULL) { + if ((mv = dict_get(settings->vasp_list, x)) != NULL) + append_vasp_status(rbody, mv, 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); + } + + mms_info(0, "mmsbox", NULL,"Admin Interface -- shuttind down on port %d", (int)settings->admin_port); +} diff --git a/mbuni/mmsc/mmsc_cfg.h b/mbuni/mmsc/mmsc_cfg.h index a11cdd4..e569ef7 100644 --- a/mbuni/mmsc/mmsc_cfg.h +++ b/mbuni/mmsc/mmsc_cfg.h @@ -33,12 +33,21 @@ typedef struct MmsProxyRelay { typedef struct MmsVasp { Octstr *id; - long short_code; + long *short_codes; /* array of short codes. */ + int num_short_codes; /* number of short codes above. */ enum {SOAP_VASP, EAIF_VASP, NONE_VASP} type; Octstr *vasp_username, *vasp_password; Octstr *vasp_url; enum {UAProf_None, UAProf_URL, UAProf_UA} send_uaprof; MM7Version_t ver; + double throughput; + + time_t delete_after; /* Set, when thingie should be deleted. */ + struct { + unsigned long mo_pdus, mt_pdus; + unsigned long mo_errors, mt_errors; + time_t start_time, last_pdu; + } stats; } MmsVasp; typedef struct MmscSettings { @@ -106,15 +115,26 @@ typedef struct MmscSettings { Octstr *wap_gw_msisdn_header; Octstr *wap_gw_ip_header; - List *vasp_list; /* of MmsVasp * */ - - MmsVasp *mms2email, *mms2mobile; + Dict *vasp_list; /* of MmsVasp *, indexed by ID */ + List *vasp_del_list; /* stuff to be deleted! */ + + MmsVasp *mms2email, *mms2mobile; + + + /* Stuff for the admin interface. */ + long admin_port; + Octstr *admin_allow_ip, *admin_deny_ip; + Octstr *admin_pass; + long admin_thread; + mCfg *cfg; /* have a pointer to it. */ } MmscSettings; /* Returns mmsc settings. */ -MmscSettings *mms_load_mmsc_settings(mCfg *cfg, List **proxyrelays); - +MmscSettings *mms_load_mmsc_settings(Octstr *fname, List **proxyrelays); +MmsVasp *mmsc_load_vasp_from_conf(MmscSettings *m, mCfgGrp *grp, + List *errors, List *warnings); +int mmsc_unload_vasp(MmscSettings *m, Octstr *id); /* do final cleanup. */ void mms_cleanup_mmsc_settings(MmscSettings *settings); /* Returns list of MmsProxyRelay */ diff --git a/mbuni/mmsc/mmsfromemail.c b/mbuni/mmsc/mmsfromemail.c index e48983d..db53c83 100644 --- a/mbuni/mmsc/mmsfromemail.c +++ b/mbuni/mmsc/mmsfromemail.c @@ -50,8 +50,6 @@ static void send_mm4_res(int mtype, Octstr *to, Octstr *sender, Octstr *transid, static void strip_quotes(Octstr *s); - -static mCfg *cfg; static List *proxyrelays; @@ -78,24 +76,15 @@ int main(int argc, char *argv[]) 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)); - - octstr_destroy(fname); - mms_info(0, "mmsfromemail", NULL, "----------------------------------------"); mms_info(0, "mmsfromemail", NULL, " MMSC Email2MMS/MM4 Incoming Tool version %s starting", MMSC_VERSION); - + /* Load settings. */ - settings = mms_load_mmsc_settings(cfg, &proxyrelays); - - mms_cfg_destroy(cfg); - + settings = mms_load_mmsc_settings(fname, &proxyrelays); if (!settings) - panic(0, "No global MMSC configuration!"); + panic(0, "No global MMSC configuration, or failed to read conf from <%s>!", octstr_get_cstr(fname)); + octstr_destroy(fname); if (!xto || !xfrom) { mms_error(0, "mmsfromemail", NULL, "usage: %s -f from -t to!", argv[0]); return -1; diff --git a/mbuni/mmsc/mmsglobalsender.c b/mbuni/mmsc/mmsglobalsender.c index 618c7e1..70c5c73 100644 --- a/mbuni/mmsc/mmsglobalsender.c +++ b/mbuni/mmsc/mmsglobalsender.c @@ -52,12 +52,14 @@ static int mms_sendtovasp(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgId List *qh, MmsMsg *m, Octstr **error); -static int _x_octstr_int_compare(int n, Octstr *s); +static int match_short_codes(Octstr *phonenum, long short_codes[], int num_codes); + +#if 0 /* Send errors */ #define MMS_SEND_OK 0 #define MMS_SEND_ERROR_TRANSIENT -1 #define MMS_SEND_ERROR_FATAL -2 - +#endif #define NMAX 256 static char qdir[NMAX]; @@ -201,7 +203,8 @@ static int sendMsg(MmsEnvelope *e) Octstr *mmsc; int sent = 0; MmsVasp *vasp; - + List *vlist; + /* If it is an IP, send to mobile handler, else if number, look for recipient. */ if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) phonenum = octstr_copy(to->rcpt, 0, j); @@ -237,9 +240,10 @@ static int sendMsg(MmsEnvelope *e) } /* Search VASP list, see what you can find... */ - for (j = 0, m = gwlist_len(settings->vasp_list); j < m; j++) - if ((vasp = gwlist_get(settings->vasp_list, j)) != NULL && - _x_octstr_int_compare(vasp->short_code, phonenum) == 0) { + vlist = dict_keys(settings->vasp_list); + for (j = 0, m = gwlist_len(vlist); j < m; j++) + if ((vasp = dict_get(settings->vasp_list, gwlist_get(vlist, j))) != NULL && + match_short_codes(phonenum, vasp->short_codes, vasp->num_short_codes)) { res = mms_sendtovasp(vasp, e->from, to->rcpt, e->msgId, e->hdrs, @@ -248,7 +252,8 @@ static int sendMsg(MmsEnvelope *e) sent = 1; break; } - + gwlist_destroy(vlist, (void *)octstr_destroy); + if (sent != 1) { /* Not yet, sent, find the receiver MMSC. */ /* Normalise the number, then see if we can resolve home MMSC for this recipient. */ #if 0 @@ -322,9 +327,12 @@ static int sendMsg(MmsEnvelope *e) } } - if (sent != 1) /* try mm7 delivery. Again. */ - for (j = 0, m = gwlist_len(settings->vasp_list); j < m; j++) - if ((vasp = gwlist_get(settings->vasp_list, j)) != NULL && + if (sent != 1) { /* try mm7 delivery. Again. */ + List *vlist = dict_keys(settings->vasp_list); + Octstr *vid; + for (j = 0, m = gwlist_len(vlist); j < m; j++) + if ((vid = gwlist_get(vlist, j)) != NULL && + (vasp = dict_get(settings->vasp_list, vid)) != NULL && vasp->id && octstr_compare(vasp->id, mmsc) == 0) { res = mms_sendtovasp(vasp, e->from, to->rcpt, @@ -335,6 +343,9 @@ static int sendMsg(MmsEnvelope *e) sent = 1; break; } + + gwlist_destroy(vlist, (void *)octstr_destroy); + } } octstr_destroy(mmsc); } @@ -390,12 +401,19 @@ static int sendMsg(MmsEnvelope *e) } /* Write to log */ - mms_info(0, "MM2", NULL, "%s Global Queue MMS Send [%.128s]: From %s, to %s, msgsize=%ld: err=%s", - SEND_ERROR_STR(res), - e->xqfname, - octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, - err ? octstr_get_cstr(err) : "(null)"); - + if (res == MMS_SEND_ERROR_FATAL) + mms_error(0, "MM2", NULL, "%s Global Queue MMS Send [%.128s]: From %s, to %s, msgsize=%ld: %s", + SEND_ERROR_STR(res), + e->xqfname, + octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, + err ? octstr_get_cstr(err) : "(null)"); + else + mms_info(0, "MM2", NULL, "%s Global Queue MMS Send [%.128s]: From %s, to %s, msgsize=%ld: %s", + SEND_ERROR_STR(res), + e->xqfname, + octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, + err ? octstr_get_cstr(err) : "(null)"); + if (res == MMS_SEND_OK && (e->msgtype == MMS_MSGTYPE_SEND_REQ || e->msgtype == MMS_MSGTYPE_RETRIEVE_CONF)) { /* Do CDR writing. */ @@ -598,7 +616,7 @@ static int _x_octstr_int_compare(int n, Octstr *s) static int mm7soap_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgId, List *qh, - MmsMsg *m, Octstr **error) + MmsMsg *m, Octstr **error, int *got_conn_error) { int ret = MMS_SEND_ERROR_TRANSIENT; int mtype = mms_messagetype(m); @@ -641,7 +659,7 @@ static int mm7soap_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgId, } hstatus = mms_url_fetch_content(HTTP_METHOD_POST, vasp->vasp_url, rh, body, &ph, &rbody); - + *got_conn_error = (hstatus < 0); if (http_status_class(hstatus) != HTTP_STATUS_SUCCESSFUL) { *error = octstr_format("Failed to contact VASP[url=%s] => HTTP returned status = %d!", octstr_get_cstr(vasp->vasp_url), hstatus); @@ -700,7 +718,7 @@ static int mm7soap_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgId, } static int mm7eaif_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgid, - MmsMsg *m, Octstr **error) + MmsMsg *m, Octstr **error, int *got_conn_error) { int ret = MMS_SEND_ERROR_TRANSIENT; int mtype = mms_messagetype(m); @@ -745,9 +763,10 @@ static int mm7eaif_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgid, } else mms_info(0, "MM7", vasp->id, "Sent to VASP[%s], code=[%d]", octstr_get_cstr(vasp->id), hstatus); - if (hstatus < 0) + if (hstatus < 0) { ret = MMS_SEND_ERROR_TRANSIENT; - else { + *got_conn_error = (hstatus < 0); + } else { hstatus = http_status_class(hstatus); if (hstatus == HTTP_STATUS_CLIENT_ERROR) ret = MMS_SEND_ERROR_TRANSIENT; @@ -771,16 +790,36 @@ static int mms_sendtovasp(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgid List *qh, MmsMsg *m, Octstr **err) { + int ret, conn_err = 0; if (m == NULL) { *err = octstr_format("GlobalSend: Failed to send to %S, Message format is corrupt!", to); - return MMS_SEND_ERROR_FATAL; + ret = MMS_SEND_ERROR_FATAL; } else if (vasp->type == SOAP_VASP) - return mm7soap_send(vasp, from, to, msgid, qh, m, err); + ret = mm7soap_send(vasp, from, to, msgid, qh, m, err, &conn_err); else if (vasp->type == EAIF_VASP) - return mm7eaif_send(vasp, from, to, msgid, m, err); + ret = mm7eaif_send(vasp, from, to, msgid, m, err, &conn_err); else { mms_error(0, "MM7", vasp->id, "Vasp[%s] of unknown type, can't send!", vasp->id ? octstr_get_cstr(vasp->id) : ""); - return MMS_SEND_ERROR_FATAL; + ret = MMS_SEND_ERROR_FATAL; } + + if (ret < 0) /* failed. */ + vasp->stats.mt_errors++; + + if (!conn_err) { + vasp->stats.mt_pdus++; + vasp->stats.last_pdu = time(NULL); + } + return ret; +} + +static int match_short_codes(Octstr *phonenum, long short_codes[], int num_codes) +{ + int i; + + for (i = 0; ivasp_username, p) == 0 && - octstr_compare(x->vasp_password, q) == 0) { - m = x; + vlist = dict_keys(vasps); + while ((x = gwlist_extract_first(vlist)) != NULL) { + MmsVasp *mv = dict_get(vasps, x); + + octstr_destroy(x); + + if (mv && + octstr_compare(mv->vasp_username, p) == 0 && + octstr_compare(mv->vasp_password, q) == 0) { + m = mv; break; } } + gwlist_destroy(vlist, NULL); /* if it can't authenticate, returns NULL. */ @@ -1543,13 +1548,17 @@ static void mm7soap_dispatch(MmsHTTPClientInfo *h) " --> Enterred mm7dispatch interface, mreq=[%s] mtype=[%s] <-- ", mreq ? "Ok" : "Null", mreq ? (char *)msgtype : "Null"); - + if (!mreq) { - mresp = mm7_make_resp(NULL, MM7_SOAP_FORMAT_CORRUPT, NULL,0); + status = MM7_SOAP_FORMAT_CORRUPT; + mresp = mm7_make_resp(NULL, status, NULL,0); goto done; } - sender = octstr_format("%d/TYPE=PLMN", h->vasp->short_code); + h->vasp->stats.mo_pdus++; + h->vasp->stats.last_pdu = time(NULL); + + sender = octstr_format("%d/TYPE=PLMN", h->vasp->short_codes[0]); /* defaults to first short code. */ switch (mm7_msgtype(mreq)) { case MM7_TAG_SubmitReq: mm7_get_envelope(mreq, &from, &to, &subject, &vasid, &expiryt, &delivert, NULL, NULL); @@ -1684,12 +1693,15 @@ static void mm7soap_dispatch(MmsHTTPClientInfo *h) mresp = mm7_make_resp(mreq, status, NULL,0); break; default: - mresp = mm7_make_resp(mreq, MM7_SOAP_UNSUPPORTED_OPERATION, NULL,0); + status = MM7_SOAP_UNSUPPORTED_OPERATION; + mresp = mm7_make_resp(mreq, status, NULL,0); break; } done: + if (!MM7_SOAP_STATUS_OK(status)) + h->vasp->stats.mo_errors++; /* increment error count. */ if (mresp && mm7_soapmsg_to_httpmsg(mresp, &h->vasp->ver, &rh, &reply_body) == 0) http_send_reply(h->client, hstatus, rh, reply_body); @@ -1720,7 +1732,6 @@ static void mm7soap_dispatch(MmsHTTPClientInfo *h) static void mm7eaif_dispatch(MmsHTTPClientInfo *h) { - /* if no vasp, return 4001 error. */ MmsMsg *m = NULL; List *mh = NULL; int hstatus = HTTP_NO_CONTENT; @@ -1749,6 +1760,9 @@ static void mm7eaif_dispatch(MmsHTTPClientInfo *h) goto done; } + h->vasp->stats.mo_pdus++; + h->vasp->stats.last_pdu = time(NULL); + mms_remove_headers(m, "Message-ID"); mh = mms_message_headers(m); /* Now get sender and receiver data. @@ -1840,6 +1854,9 @@ static void mm7eaif_dispatch(MmsHTTPClientInfo *h) http_send_reply(h->client, hstatus, rh, octstr_imm("")); + if (http_status_class(hstatus) != HTTP_OK) + h->vasp->stats.mo_errors++; + http_destroy_headers(hto); gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); octstr_destroy(hfrom); @@ -1858,15 +1875,16 @@ static void mm7proxy(void *unused) &h.body, &h.cgivars)) != NULL) if (is_allowed_ip(settings->allow_ip, settings->deny_ip, h.ip)) { MmsHTTPClientInfo *hx = gw_malloc(sizeof *hx); + int has_auth = 0; + double tdur; - /* Clear some stuff. */ h.client_addr = NULL; h.base_client_addr = NULL; h.profile_url = NULL; /* Get the MM7 sender address. */ - h.vasp = find_mm7sender(h.headers, settings->vasp_list); + h.vasp = find_mm7sender(h.headers, settings->vasp_list, &has_auth); h.ua = http_header_value(h.headers, octstr_imm("User-Agent")); debug("mmsproxy", 0, " MM7 Request, ip=%s, vasp=%s ", @@ -1888,7 +1906,21 @@ static void mm7proxy(void *unused) octstr_imm("")); http_destroy_headers(hh); free_clientInfo(hx, 1); - mms_info(0, "MM7", NULL, "MMSC: Auth failed/VASP not found in MM7 incoming connection!"); + if (!has_auth) + mms_info_ex("auth", 0, "MM7", NULL, "MMSC: Auth failed/VASP not found in MM7 incoming connection!"); + else + mms_error_ex("auth", 0, "MM7", NULL, "MMSC: Auth failed/VASP not found in MM7 incoming connection!"); + } else if (h.vasp->throughput > 0 && + (tdur = h.vasp->stats.start_time - time(NULL)) > 0 && + h.vasp->stats.mo_pdus/tdur > h.vasp->throughput) { /* throttling error, do not even process the message. */ + List *hh = http_create_empty_headers(); + http_send_reply(hx->client, 409, hh, /* respond with HTTP Conflict code. */ + octstr_imm("Throttling limit exceeded. Try again later")); + http_destroy_headers(hh); + free_clientInfo(hx, 1); + mms_error_ex("throttle", 0, "MM7", h.vasp->id, + "MMSC: VASP Exceeded throttling limit (%.2f PDU/sec). Connection reset!", + h.vasp->throughput); } else if (h.vasp->type == SOAP_VASP) gwthread_create((gwthread_func_t *)mm7soap_dispatch, hx); else diff --git a/mbuni/mmsc/mmssend.c b/mbuni/mmsc/mmssend.c index bbab82b..28b7dc4 100644 --- a/mbuni/mmsc/mmssend.c +++ b/mbuni/mmsc/mmssend.c @@ -57,7 +57,6 @@ static int find_own(int i, int argc, char *argv[]) return -1; } -static mCfg *cfg; static MmscSettings *settings; static List *proxyrelays; static MmsMsg *m; @@ -84,25 +83,17 @@ int main(int argc, char *argv[]) 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)); - - octstr_destroy(fname); - mms_info(0, "mmssend", NULL, "----------------------------------------"); mms_info(0, "mmssend", NULL, " MMSC Message sender runner version %s starting", MMSC_VERSION); /* Load settings. */ - settings = mms_load_mmsc_settings(cfg, &proxyrelays); - - mms_cfg_destroy(cfg); - + settings = mms_load_mmsc_settings(fname, &proxyrelays); + if (!settings) - panic(0, "No global MMSC configuration!"); + panic(0, "No global MMSC configuration, or failed to read conf from <%s>!", octstr_get_cstr(fname)); + octstr_destroy(fname); if (from == NULL || to == NULL) { mms_error(0, "mmssend", NULL, "Sender and recipient addresses required!\n");