1
0
Fork 0

EAIF implementation, first stab.

This commit is contained in:
bagyenda 2005-04-18 04:16:15 +00:00
parent 224866fbff
commit 2b2999a31e
5 changed files with 357 additions and 172 deletions

View File

@ -97,8 +97,9 @@ commonly called a MMS Centre).</p>
<p>Mbuni aims to
support all the major MMS interfaces, including phone-to-phone (so-called MM1
interface), phone-to-email (MM3), inter-MMSC (MM4) and MMS VAS (MM7). The
initial release fully supports the MM1 and MM3 interfaces, and provides
interface), phone-to-email (MM3), inter-MMSC (MM4) and MMS VAS
(MM7). The
current release fully supports the MM1, MM3 and MM7 interfaces, and provides
rudimentary support for the MM4 interface. This version also supports
network-side MMBox storage and transactions as specified in the OMA
MMS v1.2 specification. </p>
@ -229,8 +230,11 @@ content depending on the capabilities of the receiving terminal
<li> Support for persistent storage of messages for subscribers (MMbox).
<li> Inter-MMSC message exchange (MM4 interface)
<li> Support for integration with subscriber database to enable smart handling of handsets that do not support MMS, handsets not provisioned, etc.
<li> Support for MMS Value Added Service Providers using MM7
protocols (SOAP or EAIF).
<li> Support for integration with subscriber database to enable
smart handling of handsets that do not support MMS, handsets not
provisioned, etc.
<li> Support for flexible billing structure through billing/CDR plug-in architecture
@ -240,9 +244,7 @@ content depending on the capabilities of the receiving terminal
<p>
Currently, only the SOAP MM7 requests are supported. Nokia/EAIF is
planned and should be available soon.
<br>
The Gateway is designed and tested to conform to Open Mobile Alliance
(OMA), WAP and 3rd Generation Partnership Project (3GPP) MMS standards
including:
@ -1345,7 +1347,7 @@ mmsc-password
String
</td>
<td valign=top >
This should be one of: soap, eaif (<i>note: only soap is supported currently</i>)
This should be one of: soap, eaif
</td>
</tr>
<tr>
@ -1428,7 +1430,7 @@ mmsc-password
</table>
Note that currently only HTTP Basic authentication scheme is supported
Note that currently only HTTP Basic Authentication Scheme is supported
by Mbuni (for both incoming and out-going requests).

View File

@ -35,6 +35,8 @@
#define XIP_HEADER "X-WAP-Network-Client-IP"
#define MM_NAME "Mbuni"
#define EAIF_VERSION "3.0"
typedef struct MmsProxyRelay {
Octstr *host;
Octstr *name;

View File

@ -70,7 +70,8 @@ static int sendMsg(MmsEnvelope *e)
MmsMsg *msg = NULL;
if (!e->bill.billed) { /* Attempt to bill. */
if (e->msgtype == MMS_MSGTYPE_SEND_REQ &&
!e->bill.billed) { /* Attempt to bill if not already billed */
List *l = list_create();
double amt;
@ -460,107 +461,190 @@ static int _x_octstr_int_compare(int n, Octstr *s)
return octstr_str_compare(s,x);
}
static int mms_sendtovasp(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgId,
static int mm7soap_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgId,
MmsMsg *m, Octstr **error)
{
int ret = MMS_SEND_ERROR_TRANSIENT;
int mtype = mms_messagetype(m);
int hstatus = HTTP_OK, tstatus;
List *xto = list_create();
MSoapMsg_t *mreq = NULL, *mresp = NULL;
List *rh = NULL, *ph = NULL;
Octstr *body = NULL, *rbody = NULL, *url = NULL;
HTTPCaller *caller = http_caller_create();
void *xx;
Octstr *s;
info(0, "MMS Relay: Send to VASP[%s], msg type [%s], from %s, to %s",
info(0, "MMS Relay: Send[soap] to VASP[%s], msg type [%s], from %s, to %s",
vasp ? octstr_get_cstr(vasp->id) : "",
mms_message_type_to_cstr(mtype), octstr_get_cstr(from), octstr_get_cstr(to));
mms_message_type_to_cstr(mtype), octstr_get_cstr(from), octstr_get_cstr(to));
if (vasp->type == SOAP_VASP) {
int hstatus = HTTP_OK, tstatus;
List *xto = list_create();
MSoapMsg_t *mreq = NULL, *mresp = NULL;
List *rh = NULL, *ph = NULL;
Octstr *body = NULL, *rbody = NULL, *url = NULL;
HTTPCaller *caller = http_caller_create();
void *xx;
Octstr *s;
list_append(xto, to);
list_append(xto, to);
if ((mreq = mm7_mmsmsg_to_soap(m, from, xto, msgId, settings->host_alias)) == NULL) {
*error = octstr_format("Failed to convert Msg[%s] 2 SOAP message!",
mms_message_type_to_cstr(mtype));
goto done1;
}
if (mm7_soapmsg_to_httpmsg(mreq, &rh, &body) < 0) {
*error = octstr_format("Failed to convert SOAP message 2 HTTP Msg!");
goto done1;
}
if (vasp->mmsc_username)
http_add_basic_auth(rh, vasp->mmsc_username,
vasp->mmsc_password ? vasp->mmsc_password : octstr_imm(""));
http_start_request(caller, HTTP_METHOD_POST, vasp->vasp_url, rh, body, 1, NULL, NULL);
if ((xx = http_receive_result(caller, &hstatus, &url, &ph, &rbody)) == NULL ||
hstatus != HTTP_OK) {
*error = octstr_format("Failed to contact VASP[url=%s] => HTTP returned status = %d, id=%s !",
octstr_get_cstr(vasp->vasp_url), hstatus, xx ? "Ok" : "not OK");
goto done1;
}
if ((mresp = mm7_parse_soap(ph, rbody)) == NULL) {
*error = octstr_format("Failed to parse VASP[url=%s, id=%s] response!",
octstr_get_cstr(vasp->vasp_url),
octstr_get_cstr(vasp->id));
goto done1;
}
/* Now look at response code and use it to tell you what you want. */
if ((s = mm7_soap_header_value(mresp, octstr_imm("StatusCode"))) != NULL) {
tstatus = atoi(octstr_get_cstr(s));
octstr_destroy(s);
} else
tstatus = MM7_SOAP_FORMAT_CORRUPT;
if (!MM7_SOAP_STATUS_OK(tstatus)) {
Octstr *detail = mm7_soap_header_value(mresp, octstr_imm("Details"));
ret = MMS_SEND_ERROR_FATAL;
info(0, "Send to VASP[%s], failed, code=[%d=>%s], detail=%s",
vasp ? octstr_get_cstr(vasp->id) : "",
tstatus, mms_soap_status_to_cstr(tstatus),
detail ? octstr_get_cstr(detail) : "");
*error = octstr_format("Failed to deliver to VASP[url=%s, id=%s], status=[%d=>%s]!",
octstr_get_cstr(vasp->vasp_url),
octstr_get_cstr(vasp->id),
tstatus, mms_soap_status_to_cstr(tstatus));
if ((mreq = mm7_mmsmsg_to_soap(m, from, xto, msgId, settings->host_alias)) == NULL) {
*error = octstr_format("Failed to convert Msg[%s] 2 SOAP message!",
mms_message_type_to_cstr(mtype));
goto done1;
}
if (mm7_soapmsg_to_httpmsg(mreq, &rh, &body) < 0) {
*error = octstr_format("Failed to convert SOAP message 2 HTTP Msg!");
goto done1;
}
if (detail)
octstr_destroy(detail);
if (vasp->mmsc_username)
http_add_basic_auth(rh, vasp->mmsc_username,
vasp->mmsc_password ? vasp->mmsc_password : octstr_imm(""));
http_start_request(caller, HTTP_METHOD_POST, vasp->vasp_url, rh, body, 1, NULL, NULL);
if ((xx = http_receive_result(caller, &hstatus, &url, &ph, &rbody)) == NULL ||
hstatus != HTTP_OK) {
*error = octstr_format("Failed to contact VASP[url=%s] => HTTP returned status = %d, id=%s !",
octstr_get_cstr(vasp->vasp_url), hstatus, xx ? "Ok" : "not OK");
goto done1;
}
if ((mresp = mm7_parse_soap(ph, rbody)) == NULL) {
*error = octstr_format("Failed to parse VASP[url=%s, id=%s] response!",
octstr_get_cstr(vasp->vasp_url),
octstr_get_cstr(vasp->id));
goto done1;
}
/* Now look at response code and use it to tell you what you want. */
if ((s = mm7_soap_header_value(mresp, octstr_imm("StatusCode"))) != NULL) {
tstatus = atoi(octstr_get_cstr(s));
octstr_destroy(s);
} else
tstatus = MM7_SOAP_FORMAT_CORRUPT;
if (!MM7_SOAP_STATUS_OK(tstatus)) {
Octstr *detail = mm7_soap_header_value(mresp, octstr_imm("Details"));
ret = MMS_SEND_ERROR_FATAL;
info(0, "Send to VASP[%s], failed, code=[%d=>%s], detail=%s",
vasp ? octstr_get_cstr(vasp->id) : "",
tstatus, mms_soap_status_to_cstr(tstatus),
detail ? octstr_get_cstr(detail) : "");
*error = octstr_format("Failed to deliver to VASP[url=%s, id=%s], status=[%d=>%s]!",
octstr_get_cstr(vasp->vasp_url),
octstr_get_cstr(vasp->id),
tstatus, mms_soap_status_to_cstr(tstatus));
if (detail)
octstr_destroy(detail);
} else
ret = MMS_SEND_OK;
info(0, "Sent to VASP[%s], code=[%d=>%s]", octstr_get_cstr(vasp->id),
tstatus, mms_soap_status_to_cstr(tstatus));
done1:
if (mreq)
mm7_soap_destroy(mreq);
if (mresp)
mm7_soap_destroy(mresp);
if (rh)
http_destroy_headers(rh);
if (body)
octstr_destroy(body);
if (ph)
http_destroy_headers(ph);
if (rbody)
octstr_destroy(rbody);
if (url)
octstr_destroy(url);
http_caller_destroy(caller);
list_destroy(xto, NULL);
} /* else if EAIF, etc.. */
} else
ret = MMS_SEND_OK;
info(0, "Sent to VASP[%s], code=[%d=>%s]", octstr_get_cstr(vasp->id),
tstatus, mms_soap_status_to_cstr(tstatus));
done1:
if (mreq)
mm7_soap_destroy(mreq);
if (mresp)
mm7_soap_destroy(mresp);
if (rh)
http_destroy_headers(rh);
if (body)
octstr_destroy(body);
if (ph)
http_destroy_headers(ph);
if (rbody)
octstr_destroy(rbody);
if (url)
octstr_destroy(url);
http_caller_destroy(caller);
list_destroy(xto, NULL);
return ret;
}
static int mm7eaif_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgid,
MmsMsg *m, Octstr **error)
{
int ret = MMS_SEND_ERROR_TRANSIENT;
int mtype = mms_messagetype(m);
int hstatus = HTTP_OK;
List *rh = http_create_empty_headers(), *ph = NULL;
Octstr *body = NULL, *rbody = NULL, *url = NULL;
HTTPCaller *caller = http_caller_create();
void *xx;
char *msgtype;
info(0, "MMS Relay: Send [eaif] to VASP[%s], msg type [%s], from %s, to %s",
vasp ? octstr_get_cstr(vasp->id) : "",
mms_message_type_to_cstr(mtype), octstr_get_cstr(from), octstr_get_cstr(to));
http_header_add(rh, "X-NOKIA-MMSC-To", octstr_get_cstr(to));
http_header_add(rh, "X-NOKIA-MMSC-From", octstr_get_cstr(from));
if (msgid)
http_header_add(rh, "X-NOKIA-MMSC-Message-Id", octstr_get_cstr(from));
http_header_add(rh, "X-NOKIA-MMSC-Version", EAIF_VERSION);
if (mtype == MMS_MSGTYPE_SEND_REQ)
msgtype = "MultiMediaMessage";
else if (mtype == MMS_MSGTYPE_DELIVERY_IND)
msgtype = "DeliveryReport";
else
msgtype = "ReadReply";
http_header_add(rh, "X-NOKIA-MMSC-Message-Type", msgtype);
http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
if (vasp->mmsc_username)
http_add_basic_auth(rh, vasp->mmsc_username,
vasp->mmsc_password ? vasp->mmsc_password : octstr_imm(""));
body = mms_tobinary(m);
http_start_request(caller, HTTP_METHOD_POST, vasp->vasp_url, rh, body, 1, NULL, NULL);
if ((xx = http_receive_result(caller, &hstatus, &url, &ph, &rbody)) == NULL ||
http_status_class(hstatus) != HTTP_STATUS_SUCCESSFUL) {
*error = octstr_format("Failed to contact VASP[url=%s] => HTTP returned status = %d, id=%s !",
octstr_get_cstr(vasp->vasp_url), hstatus, xx ? "Ok" : "not OK");
} else
info(0, "Sent to VASP[%s], code=[%d]", octstr_get_cstr(vasp->id), hstatus);
if (hstatus < 0)
ret = MMS_SEND_ERROR_TRANSIENT;
else {
hstatus = http_status_class(hstatus);
if (hstatus == HTTP_STATUS_CLIENT_ERROR)
ret = MMS_SEND_ERROR_TRANSIENT;
else if (hstatus == HTTP_STATUS_SERVER_ERROR)
ret = MMS_SEND_ERROR_FATAL;
else
ret = MMS_SEND_OK;
}
if (rh)
http_destroy_headers(rh);
if (body)
octstr_destroy(body);
if (ph)
http_destroy_headers(ph);
if (rbody)
octstr_destroy(rbody);
if (url)
octstr_destroy(url);
http_caller_destroy(caller);
return ret;
}
static int mms_sendtovasp(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgid,
MmsMsg *m, Octstr **err)
{
if (vasp->type == SOAP_VASP)
return mm7soap_send(vasp, from, to, msgid, m, err);
else if (vasp->type == EAIF_VASP)
return mm7eaif_send(vasp, from, to, msgid, m, err);
else {
error(0, "Vasp[%s] of unknown type, can't send!",
vasp->id ? octstr_get_cstr(vasp->id) : "");
return MMS_SEND_ERROR_FATAL;
}
}

View File

@ -22,6 +22,7 @@
#include "mms_util.h"
#include "mms_mm7soap.h"
static Cfg *cfg;
static List *proxyrelays;
static MmsBoxSettings *settings;
@ -48,6 +49,7 @@ typedef struct MmsHTTPClientInfo {
MmsVasp *vasp;
} MmsHTTPClientInfo;
static void free_clientInfo(MmsHTTPClientInfo *h, int freeh);
static void fetchmms_proxy(MmsHTTPClientInfo *h);
static void sendmms_proxy(MmsHTTPClientInfo *h);
@ -82,7 +84,7 @@ int main(int argc, char *argv[])
octstr_destroy(fname);
info(0, "----------------------------------------");
info(0, " MMSC Proxy Relay server version %s starting", MMSC_VERSION);
info(0, " " MM_NAME " MMSC Proxy version %s starting", MMSC_VERSION);
grp = cfg_get_single_group(cfg, octstr_imm("core"));
log = cfg_get(grp, octstr_imm("log-file"));
@ -407,20 +409,7 @@ void fetchmms_proxy(MmsHTTPClientInfo *h)
if (token) octstr_destroy(token);
if (transid) octstr_destroy(transid);
octstr_destroy(h->ip);
octstr_destroy(h->url);
if (h->ua) octstr_destroy(h->ua);
if (h->body) octstr_destroy(h->body);
if (h->base_client_addr)
octstr_destroy(h->base_client_addr);
octstr_destroy(h->client_addr);
http_destroy_cgiargs(h->cgivars);
http_destroy_headers(h->headers);
gw_free(h);
free_clientInfo(h,1);
}
/* Make list of recipients and also sender. */
@ -1565,21 +1554,7 @@ static void sendmms_proxy(MmsHTTPClientInfo *h)
if (reply_body)
octstr_destroy(reply_body);
octstr_destroy(h->ip);
octstr_destroy(h->url);
if (h->base_client_addr)
octstr_destroy(h->base_client_addr);
if (h->client_addr)
octstr_destroy(h->client_addr);
if (h->ua) octstr_destroy(h->ua);
if (h->body) octstr_destroy(h->body);
http_destroy_cgiargs(h->cgivars);
http_destroy_headers(h->headers);
gw_free(h);
free_clientInfo(h,1);
}
/* Find sender credentials: only auth-basic supported for now. */
@ -1626,7 +1601,7 @@ static MmsVasp *find_mm7sender(List *headers, List *vasps)
return m;
}
static void mm7dispatch(MmsHTTPClientInfo *h)
static void mm7soap_dispatch(MmsHTTPClientInfo *h)
{
/* if no vasp, return 4001 error. */
MSoapMsg_t *mreq = NULL, *mresp = NULL;
@ -1653,14 +1628,7 @@ static void mm7dispatch(MmsHTTPClientInfo *h)
mreq ? msgtype : "Null");
if (!h->vasp) {
/* 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, 401, hh, octstr_imm(""));
goto done2;
} else if (!mreq) {
if (!mreq) {
mresp = mm7_make_resp(NULL, 2007, NULL);
goto done;
}
@ -1805,7 +1773,6 @@ static void mm7dispatch(MmsHTTPClientInfo *h)
else
http_close_client(h->client);
done2:
if (e)
mms_queue_free_env(e);
@ -1839,23 +1806,132 @@ static void mm7dispatch(MmsHTTPClientInfo *h)
if (to)
list_destroy(to, (list_item_destructor_t *)octstr_destroy);
octstr_destroy(h->ip);
octstr_destroy(h->url);
if (h->base_client_addr)
octstr_destroy(h->base_client_addr);
if (h->client_addr)
octstr_destroy(h->client_addr);
if (h->ua) octstr_destroy(h->ua);
if (h->body) octstr_destroy(h->body);
http_destroy_cgiargs(h->cgivars);
http_destroy_headers(h->headers);
gw_free(h);
free_clientInfo(h,1);
}
static void mm7eaif_dispatch(MmsHTTPClientInfo *h)
{
/* if no vasp, return 4001 error. */
MmsMsg *m = NULL;
List *mh = NULL;
int hstatus = HTTP_NO_CONTENT;
List *rh = http_create_empty_headers();
Octstr *reply_body = NULL, *value;
List *to = list_create(), *hto = NULL;
Octstr *subject = NULL, *otransid = NULL, *msgid = NULL;
Octstr *hfrom = NULL;
time_t expiryt = -1, deliveryt = -1;
Octstr *qf = NULL;
int msize = h->body ? octstr_len(h->body) : 0;
int dlr;
debug("mm7eaif.sendinterface", 0,
" --> Enterred eaif send interface, blen=%d <--- ",
msize);
hfrom = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-From"));
if (!h->body || /* A body is required, and must parse */
(m = mms_frombinary(h->body, hfrom ? hfrom : octstr_imm("anon@anon"))) == NULL) {
http_header_add(rh, "Content-Type", "text/plain");
hstatus = HTTP_BAD_REQUEST;
reply_body = octstr_format("Unexpected MMS message, no body?");
goto done;
}
mh = mms_message_headers(m);
/* Now get sender and receiver data.
* for now we ignore adaptation flags.
*/
collect_senddata(mh, &to, &subject, &otransid, &expiryt, &deliveryt);
if ((hto = http_header_find_all(h->headers, "X-NOKIA-MMSC-To")) != NULL &&
list_len(hto) > 0) { /* To address is in headers. */
int i, n;
if (to)
list_destroy(to, (list_item_destructor_t *)octstr_destroy);
to = list_create();
for (i = 0, n = list_len(hto); i < n; i++) {
Octstr *h = NULL, *v = NULL;
List *l;
int j, m;
http_header_get(hto,i, &h, &v);
l = http_header_split_value(v);
for (j = 0, m = list_len(l); j < m; j++)
list_append(to, list_get(l, j));
list_destroy(l, NULL);
if (h) octstr_destroy(h);
if (v) octstr_destroy(v);
}
}
value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report"));
if (value &&
octstr_case_compare(value, octstr_imm("Yes")) == 0)
dlr = 1;
else
dlr = 0;
if (value)
octstr_destroy(value);
if (deliveryt < 0)
deliveryt = time(NULL);
if (expiryt < 0)
expiryt = time(NULL) + settings->default_msgexpiry;
/* Save it, make msgid, put message id in header, return. */
qf = mms_queue_add(hfrom, to, subject,
NULL, NULL, deliveryt, expiryt, m, NULL,
NULL, NULL,
dlr,
octstr_get_cstr(settings->global_queuedir),
settings->host_alias);
if (qf) {
msgid = mms_maketransid(octstr_get_cstr(qf),
settings->host_alias);
/* Log to access log */
mms_log("Received", hfrom, to, msize, msgid, h->vasp->id, NULL, "MM7", h->ua, NULL);
octstr_destroy(qf);
hstatus = HTTP_NO_CONTENT;
} else
hstatus = HTTP_INTERNAL_SERVER_ERROR;
done:
http_header_add(rh, "X-NOKIA-MMSC-Version", EAIF_VERSION);
if (msgid)
http_header_add(rh, "X-NOKIA-MMSC-Message-Id", octstr_get_cstr(msgid));
http_send_reply(h->client, hstatus, rh, octstr_imm(""));
if (hto)
http_destroy_headers(hto);
if (to)
list_destroy(to, (list_item_destructor_t *)octstr_destroy);
if (hfrom)
octstr_destroy(hfrom);
if (subject)
octstr_destroy(subject);
if (otransid)
octstr_destroy(otransid);
if (msgid)
octstr_destroy(msgid);
if (mh)
http_destroy_headers(mh);
if (m) mms_destroy(m);
}
static void mm7proxy(void *unused)
{
MmsHTTPClientInfo h;
@ -1875,7 +1951,7 @@ static void mm7proxy(void *unused)
debug("mmsproxy", 0,
" MM7 Request, ip=%s, vasp=%s ",
h.ip ? octstr_get_cstr(h.ip) : "",
h.vasp && h.vasp->id ? octstr_get_cstr(h.vasp->id) : "(null)");
h.vasp && h.vasp->id ? octstr_get_cstr(h.vasp->id) : "(null)");
/* Dump headers, url etc. */
#if 1
@ -1884,21 +1960,42 @@ static void mm7proxy(void *unused)
if (h.ip) octstr_dump(h.ip, 0);
#endif
*hx = h; /* Copy it all over. */
gwthread_create((gwthread_func_t *)mm7dispatch, hx);
if (!h.vasp) { /* Ask it to authenticate... */
List *hh = http_create_empty_headers();
http_header_add(hh, "WWW-Authenticate",
"Basic realm=\"" MM_NAME "\"");
http_send_reply(hx->client, HTTP_UNAUTHORIZED, hh,
octstr_imm(""));
http_destroy_headers(hh);
free_clientInfo(hx, 1);
} else if (h.vasp->type == SOAP_VASP)
gwthread_create((gwthread_func_t *)mm7soap_dispatch, hx);
else
gwthread_create((gwthread_func_t *)mm7eaif_dispatch, hx);
} else {
octstr_destroy(h.ip);
octstr_destroy(h.url);
if (h.body)
octstr_destroy(h.body);
if (h.headers)
http_destroy_headers(h.headers);
if (h.cgivars)
http_destroy_headers(h.cgivars);
free_clientInfo(&h, 0);
http_close_client(h.client);
}
debug("proxy", 0, "MM7 Shutting down...");
}
static void free_clientInfo(MmsHTTPClientInfo *h, int freeh)
{
if (h->ip)
octstr_destroy(h->ip);
if (h->url)
octstr_destroy(h->url);
if (h->ua) octstr_destroy(h->ua);
if (h->body) octstr_destroy(h->body);
if (h->base_client_addr)
octstr_destroy(h->base_client_addr);
octstr_destroy(h->client_addr);
http_destroy_cgiargs(h->cgivars);
http_destroy_headers(h->headers);
if (freeh)
gw_free(h);
}

View File

@ -53,7 +53,7 @@ int main(int argc, char *argv[])
octstr_destroy(fname);
info(0, "----------------------------------------");
info(0, " MMSC Relay version %s starting", MMSC_VERSION);
info(0, " " MM_NAME " MMSC Relay version %s starting", MMSC_VERSION);
grp = cfg_get_single_group(cfg, octstr_imm("core"));
log = cfg_get(grp, octstr_imm("log-file"));