Apparently handling registration correctly

This commit is contained in:
Pierre Pronchery 2012-08-29 23:23:37 +00:00
parent 04f0ccf7ef
commit b1247525fa

View File

@ -37,7 +37,8 @@ typedef struct _ModemPlugin
su_root_t * root; su_root_t * root;
guint source; guint source;
nua_t * nua; nua_t * nua;
nua_handle_t * handle; nua_handle_t ** handles;
size_t handles_cnt;
} Sofia; } Sofia;
@ -46,23 +47,30 @@ static ModemConfig _sofia_config[] =
{ {
{ "username", "Username", MCT_STRING }, { "username", "Username", MCT_STRING },
{ "fullname", "Full name", MCT_STRING }, { "fullname", "Full name", MCT_STRING },
{ NULL, "Registrar", MCT_SUBSECTION }, { NULL, "Network:", MCT_SUBSECTION },
{ "bind", "Bind address", MCT_STRING },
{ NULL, "Registrar:", MCT_SUBSECTION },
{ "registrar_hostname", "Hostname", MCT_STRING }, { "registrar_hostname", "Hostname", MCT_STRING },
{ "registrar_username", "Username", MCT_STRING }, { "registrar_username", "Username", MCT_STRING },
{ "registrar_password", "Password", MCT_PASSWORD }, { "registrar_password", "Password", MCT_PASSWORD },
{ NULL, "Proxy", MCT_SUBSECTION }, { NULL, "Proxy:", MCT_SUBSECTION },
{ "proxy_hostname", "Hostname", MCT_STRING }, { "proxy_hostname", "Hostname", MCT_STRING },
{ NULL, NULL, MCT_NONE }, { NULL, NULL, MCT_NONE },
}; };
/* prototypes */ /* prototypes */
/* plug-in */
static ModemPlugin * _sofia_init(ModemPluginHelper * helper); static ModemPlugin * _sofia_init(ModemPluginHelper * helper);
static void _sofia_destroy(ModemPlugin * modem); static void _sofia_destroy(ModemPlugin * modem);
static int _sofia_start(ModemPlugin * modem, unsigned int retry); static int _sofia_start(ModemPlugin * modem, unsigned int retry);
static int _sofia_stop(ModemPlugin * modem); static int _sofia_stop(ModemPlugin * modem);
static int _sofia_request(ModemPlugin * modem, ModemRequest * request); static int _sofia_request(ModemPlugin * modem, ModemRequest * request);
/* useful */
static nua_handle_t * _sofia_handle_add(Sofia * sofia, sip_to_t * to);
static int _sofia_handle_remove(Sofia * sofia, nua_handle_t * handle);
/* callbacks */ /* callbacks */
static void _sofia_callback(nua_event_t event, int status, char const * phrase, static void _sofia_callback(nua_event_t event, int status, char const * phrase,
nua_t * nua, nua_magic_t * magic, nua_handle_t * nh, nua_t * nua, nua_magic_t * magic, nua_handle_t * nh,
@ -106,6 +114,8 @@ static ModemPlugin * _sofia_init(ModemPluginHelper * helper)
} }
gsource = su_glib_root_gsource(sofia->root); gsource = su_glib_root_gsource(sofia->root);
sofia->source = g_source_attach(gsource, g_main_context_default()); sofia->source = g_source_attach(gsource, g_main_context_default());
sofia->handles = NULL;
sofia->handles_cnt = 0;
return sofia; return sofia;
} }
@ -131,70 +141,85 @@ static int _sofia_start(ModemPlugin * modem, unsigned int retry)
{ {
Sofia * sofia = modem; Sofia * sofia = modem;
ModemPluginHelper * helper = sofia->helper; ModemPluginHelper * helper = sofia->helper;
char const * username;
char const * fullname;
url_string_t us; url_string_t us;
char const * s; char const * p;
url_t * url; char const * q;
sip_from_t * from; nua_handle_t * handle;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__); fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif #endif
if(sofia->nua != NULL) /* already started */ if(sofia->nua != NULL) /* already started */
return 0; return 0;
/* bind address */
if((p = helper->config_get(helper->modem, "bind")) != NULL
&& strlen(p) > 0)
snprintf(us.us_str, sizeof(us.us_str), "%s%s", "sip:", p);
else
p = NULL;
/* initialization */
if((sofia->nua = nua_create(sofia->root, _sofia_callback, modem, if((sofia->nua = nua_create(sofia->root, _sofia_callback, modem,
NUTAG_URL("sip:0.0.0.0:5060"), TAG_IF(p, NUTAG_URL(us.us_str)),
SOATAG_AF(SOA_AF_IP4_IP6),
TAG_END())) == NULL) TAG_END())) == NULL)
return -1; return -1;
/* username */ /* username */
username = helper->config_get(helper->modem, "username"); if((p = helper->config_get(helper->modem, "username")) != NULL
fullname = helper->config_get(helper->modem, "fullname"); && strlen(p) > 0)
/* registrar */ nua_set_params(sofia->nua, NUTAG_M_USERNAME(p), TAG_END());
s = helper->config_get(helper->modem, "registrar_hostname"); /* fullname */
url = url_make(sofia->home, s); if((p = helper->config_get(helper->modem, "fullname")) != NULL
nua_set_params(sofia->nua, NUTAG_REGISTRAR(url), TAG_END()); && strlen(p) > 0)
s = helper->config_get(helper->modem, "registrar_username"); nua_set_params(sofia->nua, NUTAG_M_DISPLAY(p), TAG_END());
/* XXX url_make() doesn't prefix with the protocol */
snprintf(us.us_str, sizeof(us.us_str), "%s%s", "sip:", s);
url = url_make(sofia->home, us.us_str);
us.us_url[0] = *url;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() sip_from_create(\"%s\")\n", __func__,
us.us_str);
#endif
from = sip_from_create(sofia->home, &us);
/* proxy */ /* proxy */
if((s = helper->config_get(helper->modem, "proxy_hostname")) != NULL) if((p = helper->config_get(helper->modem, "proxy_hostname")) != NULL
&& strlen(p) > 0)
{ {
url = url_make(sofia->home, s); snprintf(us.us_str, sizeof(us.us_str), "%s%s", "sip:", p);
nua_set_params(sofia->nua, NUTAG_PROXY(url), TAG_END()); nua_set_params(sofia->nua, NUTAG_PROXY(us.us_str), TAG_END());
} }
if((sofia->handle = nua_handle(sofia->nua, modem, TAG_END())) == NULL) /* registration */
return -helper->error(helper->modem, if((p = helper->config_get(helper->modem, "registrar_username"))
"Cannot create operation handle", 1); != NULL && strlen(p) > 0
#ifdef DEBUG && (q = helper->config_get(helper->modem,
fprintf(stderr, "DEBUG: %s() nua_register(\"%s\", \"%s\", \"%s\")\n", "registrar_hostname")) != NULL
__func__, username, fullname, us.us_str); && strlen(q) > 0)
#endif {
nua_register(sofia->handle, NUTAG_M_USERNAME(username), if((handle = _sofia_handle_add(sofia, NULL)) == NULL)
NUTAG_M_DISPLAY(fullname), SIPTAG_FROM(from), return -helper->error(helper->modem,
"Cannot create registration handle", 1);
snprintf(us.us_str, sizeof(us.us_str), "%s%s", "sip:", q);
nua_set_params(sofia->nua, NUTAG_REGISTRAR(us.us_str),
TAG_END()); TAG_END());
snprintf(us.us_str, sizeof(us.us_str), "%s%s@%s", "sip:", p, q);
nua_register(handle, SIPTAG_FROM_STR(us.us_str), TAG_END());
}
nua_set_params(sofia->nua, NUTAG_ENABLEMESSAGE(1),
NUTAG_ENABLEINVITE(1),
NUTAG_AUTOALERT(1),
NUTAG_AUTOANSWER(0),
TAG_END());
nua_get_params(sofia->nua, TAG_ANY(), TAG_END());
return 0; return 0;
} }
/* sofia_stop */ /* sofia_stop */
static void _stop_handle(nua_handle_t ** handle); static void _stop_handle(nua_handle_t * handle);
static int _sofia_stop(ModemPlugin * modem) static int _sofia_stop(ModemPlugin * modem)
{ {
Sofia * sofia = modem; Sofia * sofia = modem;
size_t i;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__); fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif #endif
_stop_handle(&sofia->handle); for(i = 0; i < sofia->handles_cnt; i++)
_stop_handle(sofia->handles[i]);
free(sofia->handles);
sofia->handles = NULL;
sofia->handles_cnt = 0;
if(sofia->nua != NULL) if(sofia->nua != NULL)
{ {
nua_shutdown(sofia->nua); nua_shutdown(sofia->nua);
@ -205,12 +230,11 @@ static int _sofia_stop(ModemPlugin * modem)
return 0; return 0;
} }
static void _stop_handle(nua_handle_t ** handle) static void _stop_handle(nua_handle_t * handle)
{ {
if(*handle == NULL) if(handle == NULL)
return; return;
nua_handle_destroy(*handle); nua_handle_destroy(handle);
*handle = NULL;
} }
@ -237,50 +261,98 @@ static int _sofia_request(ModemPlugin * modem, ModemRequest * request)
static int _request_call(ModemPlugin * modem, ModemRequest * request) static int _request_call(ModemPlugin * modem, ModemRequest * request)
{ {
Sofia * sofia = modem; Sofia * sofia = modem;
url_t * url; ModemPluginHelper * helper = sofia->helper;
nua_handle_t * handle;
url_string_t us; url_string_t us;
sip_to_t * to; sip_to_t * to;
if(sofia->handle == NULL || nua_handle_has_active_call(sofia->handle)) snprintf(us.us_str, sizeof(us.us_str), "%s%s", "sip:",
/* FIXME report error, keep track, allow multiple */ request->call.number);
return -1; #ifdef DEBUG
if((url = url_make(sofia->home, request->call.number)) == NULL) fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, us.us_str);
return -1; #endif
us.us_url[0] = *url; if((to = sip_to_make(sofia->home, us.us_str)) == NULL)
if((to = sip_to_create(NULL, &us)) == NULL) return -helper->error(helper->modem,
return -1; /* XXX free url */ "Could not initiate the call", 1);
if((handle = _sofia_handle_add(sofia, to)) == NULL)
return -helper->error(helper->modem,
"Could not initiate the call", 1);
to->a_display = request->call.number; to->a_display = request->call.number;
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s() nua_invite(\"%s\")\n", __func__, fprintf(stderr, "DEBUG: %s() nua_invite(\"%s\")\n", __func__,
us.us_str); us.us_str);
#endif #endif
nua_invite(sofia->handle, SIPTAG_TO(to), TAG_END()); nua_invite(handle, SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
/* FIXME free url? more? */ SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_END());
return 0; return 0;
} }
static int _request_message_send(ModemPlugin * modem, ModemRequest * request) static int _request_message_send(ModemPlugin * modem, ModemRequest * request)
{ {
Sofia * sofia = modem; Sofia * sofia = modem;
ModemPluginHelper * helper = sofia->helper;
url_string_t us; url_string_t us;
sip_to_t * to;
nua_handle_t * handle;
if(sofia->handle == NULL)
/* FIXME report error */
return -1;
snprintf(us.us_str, sizeof(us.us_str), "%s%s", "sip:", snprintf(us.us_str, sizeof(us.us_str), "%s%s", "sip:",
request->message_send.number); request->message_send.number);
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, us.us_str); fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, us.us_str);
#endif #endif
nua_message(sofia->handle, if((to = sip_to_make(sofia->home, us.us_str)) == NULL)
NUTAG_URL(&us), return -helper->error(helper->modem, "Could not send message",
SIPTAG_CONTENT_TYPE_STR("text/plain"), 1);
if((handle = _sofia_handle_add(sofia, to)) == NULL)
return -helper->error(helper->modem, "Could not send message",
1);
nua_message(handle, SIPTAG_CONTENT_TYPE_STR("text/plain"),
SIPTAG_PAYLOAD_STR(request->message_send.content), SIPTAG_PAYLOAD_STR(request->message_send.content),
TAG_END()); TAG_END());
return 0; return 0;
} }
/* useful */
/* sofia_handle_add */
static nua_handle_t * _sofia_handle_add(Sofia * sofia, sip_to_t * to)
{
size_t i;
nua_handle_t ** p;
for(i = 0; i < sofia->handles_cnt; i++)
if(sofia->handles[i] == NULL)
break;
if(i == sofia->handles_cnt)
{
if((p = realloc(sofia->handles, sizeof(*p) * (i + 1))) == NULL)
return NULL;
sofia->handles = p;
sofia->handles_cnt++;
}
sofia->handles[i] = nua_handle(sofia->nua, sofia,
TAG_IF(to, SIPTAG_TO(to)), TAG_END());
return sofia->handles[i];
}
/* sofia_handle_remove */
static int _sofia_handle_remove(Sofia * sofia, nua_handle_t * handle)
{
size_t i;
for(i = 0; i < sofia->handles_cnt; i++)
if(sofia->handles[i] == handle)
{
/* FIXME also free memory */
nua_handle_destroy(sofia->handles[i]);
sofia->handles[i] = NULL;
return 0;
}
return -1;
}
/* callbacks */ /* callbacks */
/* sofia_callback */ /* sofia_callback */
static void _callback_message(ModemPlugin * modem, int status, static void _callback_message(ModemPlugin * modem, int status,
@ -307,12 +379,24 @@ static void _sofia_callback(nua_event_t event, int status, char const * phrase,
/* FIXME report error */ /* FIXME report error */
fprintf(stderr, "i_error %03d %s\n", status, phrase); fprintf(stderr, "i_error %03d %s\n", status, phrase);
break; break;
case nua_i_invite:
/* FIXME report event: incoming call */
fprintf(stderr, "i_invite %03d %s\n", status, phrase);
break;
case nua_i_cancel:
/* FIXME report event: incoming call was cancelled */
fprintf(stderr, "i_invite %03d %s\n", status, phrase);
break;
case nua_i_notify: case nua_i_notify:
/* FIXME report event */ /* FIXME report event */
fprintf(stderr, "i_notify %03d %s\n", status, phrase); fprintf(stderr, "i_notify %03d %s\n", status, phrase);
break; break;
case nua_i_outbound:
/* FIXME what to do? */
fprintf(stderr, "i_outbound %03d %s\n", status, phrase);
break;
case nua_i_state: case nua_i_state:
/* FIXME report event */ /* FIXME report event, particularly if 180 Ringing! */
fprintf(stderr, "i_state %03d %s\n", status, phrase); fprintf(stderr, "i_state %03d %s\n", status, phrase);
break; break;
case nua_i_terminated: case nua_i_terminated:
@ -341,6 +425,13 @@ static void _sofia_callback(nua_event_t event, int status, char const * phrase,
} }
helper->event(helper->modem, &mevent); helper->event(helper->modem, &mevent);
break; break;
case nua_r_get_params:
if(status == 200)
break;
/* FIXME what to do? */
fprintf(stderr, "r_get_params %03d %s\n", status,
phrase);
break;
case nua_r_message: case nua_r_message:
_callback_message(modem, status, phrase); _callback_message(modem, status, phrase);
break; break;
@ -397,6 +488,7 @@ static void _callback_register(ModemPlugin * modem, int status,
ModemPluginHelper * helper = sofia->helper; ModemPluginHelper * helper = sofia->helper;
ModemEvent mevent; ModemEvent mevent;
sip_www_authenticate_t const * wa; sip_www_authenticate_t const * wa;
char const * hostname;
char const * username; char const * username;
char const * password; char const * password;
char const * scheme; char const * scheme;
@ -418,7 +510,9 @@ static void _callback_register(ModemPlugin * modem, int status,
mevent.registration.status mevent.registration.status
= MODEM_REGISTRATION_STATUS_SEARCHING; = MODEM_REGISTRATION_STATUS_SEARCHING;
wa = (sip != NULL) ? sip->sip_www_authenticate : NULL; wa = (sip != NULL) ? sip->sip_www_authenticate : NULL;
tl_gets(tags, SIPTAG_WWW_AUTHENTICATE_REF(wa), TAG_NULL()); tl_gets(tags, SIPTAG_WWW_AUTHENTICATE_REF(wa), TAG_END());
hostname = helper->config_get(helper->modem,
"registrar_hostname");
username = helper->config_get(helper->modem, username = helper->config_get(helper->modem,
"registrar_username"); "registrar_username");
password = helper->config_get(helper->modem, password = helper->config_get(helper->modem,
@ -427,8 +521,9 @@ static void _callback_register(ModemPlugin * modem, int status,
{ {
scheme = wa->au_scheme; scheme = wa->au_scheme;
realm = msg_params_find(wa->au_params, "realm="); realm = msg_params_find(wa->au_params, "realm=");
authstring = su_sprintf(sofia->home, "%s:%s:%s:%s", authstring = su_sprintf(sofia->home, "%s:%s:%s@%s:%s",
scheme, realm, username, password); scheme, realm, username, hostname,
password);
#ifdef DEBUG #ifdef DEBUG
fprintf(stderr, "DEBUG: %s() authstring=\"%s\"\n", fprintf(stderr, "DEBUG: %s() authstring=\"%s\"\n",
__func__, authstring); __func__, authstring);