Commit f2712512 authored by Pekka Pessi's avatar Pekka Pessi
Browse files

nua/test_proxy.h, nua/test_proxy.c: added support for multiple domains

Each domain has its own registrar and authentication module.

darcs-hash:20070713164733-65a35-4b6603ef64895272c4ac73fe952a54f37ee5f9e9.gz
parent 28395d37
......@@ -35,14 +35,17 @@
#include <string.h>
struct proxy;
struct proxy_transaction;
struct domain;
union proxy_or_domain;
struct proxy_tr;
struct client_tr;
struct registration_entry;
struct binding;
#define SU_ROOT_MAGIC_T struct proxy
#define NTA_LEG_MAGIC_T struct proxy
#define NTA_OUTGOING_MAGIC_T struct proxy_transaction
#define NTA_INCOMING_MAGIC_T struct proxy_transaction
#define NTA_LEG_MAGIC_T union proxy_or_domain
#define NTA_OUTGOING_MAGIC_T struct client_tr
#define NTA_INCOMING_MAGIC_T struct proxy_tr
#include <sofia-sip/su_wait.h>
#include <sofia-sip/nta.h>
......@@ -83,50 +86,74 @@ STORAGE void PREFIX ##_remove(T *node) \
} \
extern int LIST_DUMMY_VARIABLE
#include "test_proxy.h"
#include <test_proxy.h>
#include <sofia-sip/auth_module.h>
struct proxy {
su_home_t home[1];
void *magic;
su_root_t *parent;
su_clone_r clone;
tagi_t *tags;
su_root_t *root;
auth_mod_t *auth;
nta_agent_t *agent;
url_t const *uri;
nta_leg_t *defleg;
url_t const *rr_uri;
nta_leg_t *example_net;
nta_leg_t *example_org;
nta_leg_t *example_com;
nta_leg_t *defleg;
sip_contact_t *transport_contacts;
struct proxy_transaction *stateless;
struct proxy_transaction *transactions;
struct registration_entry *entries;
struct proxy_tr *stateless;
struct proxy_tr *transactions;
struct domain *domains;
struct {
sip_time_t min_expires, expires, max_expires;
sip_time_t session_expires, min_se;
int outbound_tcp; /**< Use inbound TCP connection as outbound */
} prefs;
};
struct domain {
su_home_t home[1];
void *magic;
struct proxy *proxy;
struct domain *next, **prev;
url_t *uri;
nta_leg_t *rleg, *uleg;
auth_mod_t *auth;
struct registration_entry *entries;
struct {
sip_time_t min_expires, expires, max_expires;
int outbound_tcp; /**< Use inbound TCP connection as outbound */
int authorize;
} prefs;
tagi_t *tags;
};
LIST_PROTOS(static, domain, struct domain);
static int _domain_init(void *_d);
static int domain_init(struct domain *domain);
static void domain_destroy(struct domain *domain);
LIST_BODIES(static, domain, struct domain, next, prev);
LIST_PROTOS(static, registration_entry, struct registration_entry);
static struct registration_entry *registration_entry_new(struct proxy *,
static struct registration_entry *registration_entry_new(struct domain *,
url_t const *);
static void registration_entry_destroy(struct registration_entry *e);
struct registration_entry
{
struct registration_entry *next, **prev;
struct proxy *proxy; /* backpointer */
struct domain *domain; /* backpointer */
url_t *aor; /* address-of-record */
struct binding *bindings; /* list of bindings */
sip_contact_t *contacts;
......@@ -145,7 +172,7 @@ struct binding
static struct binding *binding_new(su_home_t *home,
sip_contact_t *contact,
tport_t *tport,
sip_call_id_t *call_id,
sip_call_id_t const *call_id,
uint32_t cseq,
sip_time_t registered,
sip_time_t expires);
......@@ -157,51 +184,75 @@ static int binding_is_active(struct binding const *b)
(b->tport == NULL || tport_is_clear_to_send(b->tport));
}
LIST_PROTOS(static, proxy_transaction, struct proxy_transaction);
struct proxy_transaction *proxy_transaction_new(struct proxy *);
static void proxy_transaction_destroy(struct proxy_transaction *t);
LIST_PROTOS(static, proxy_tr, struct proxy_tr);
struct proxy_tr *proxy_tr_new(struct proxy *);
static void proxy_tr_destroy(struct proxy_tr *t);
struct proxy_transaction
struct proxy_tr
{
struct proxy_transaction *next, **prev;
struct proxy_tr *next, **prev;
struct proxy *proxy; /* backpointer */
sip_request_t *rq; /* request line */
struct domain *origin; /* originating domain */
struct domain *domain; /* destination domain */
sip_time_t now; /* when received */
nta_incoming_t *server; /* server transaction */
nta_outgoing_t *client; /* client transaction */
msg_t *msg; /* request message */
sip_t *sip; /* request headers */
sip_method_t method; /* request method */
int status; /* best status */
url_t *target; /* request-URI */
struct client_tr *clients; /* client transactions */
struct registration_entry *entry;
/* Registration entry */
auth_mod_t *am; /* Authentication module */
auth_status_t *as; /* Authentication status */
unsigned use_auth; /* Authentication method (401/407) to use */
unsigned rr:1;
};
LIST_PROTOS(static, client_tr, struct client_tr);
struct client_tr
{
struct client_tr *next, **prev;
struct proxy_tr *t;
int status; /* response status */
sip_request_t *rq; /* request line */
msg_t *msg; /* request message */
sip_t *sip; /* request headers */
nta_outgoing_t *client; /* transaction */
};
LIST_BODIES(static, client_tr, struct client_tr, next, prev);
static sip_contact_t *create_transport_contacts(struct proxy *p);
static int proxy_request(struct proxy *proxy,
union proxy_or_domain { struct proxy proxy[1]; struct domain domain[1]; };
static int proxy_request(union proxy_or_domain *proxy,
nta_leg_t *leg,
nta_incoming_t *irq,
sip_t const *sip);
static int proxy_ack_cancel(struct proxy_transaction *t,
nta_incoming_t *irq,
sip_t const *sip);
static int proxy_response(struct proxy_transaction *t,
nta_outgoing_t *client,
sip_t const *sip);
static int process_register(struct proxy *proxy,
nta_incoming_t *irq,
sip_t const *sip);
static int domain_request(struct proxy *proxy,
static int domain_request(union proxy_or_domain *domain,
nta_leg_t *leg,
nta_incoming_t *irq,
sip_t const *sip);
static int process_options(struct proxy *proxy,
nta_incoming_t *irq,
static int proxy_response(struct client_tr *client,
nta_outgoing_t *orq,
sip_t const *sip);
static struct registration_entry *
registration_entry_find(struct proxy const *proxy, url_t const *uri);
static int close_tports(void *proxy);
static auth_challenger_t registrar_challenger[1];
......@@ -211,7 +262,8 @@ static auth_challenger_t proxy_challenger[1];
static int
test_proxy_init(su_root_t *root, struct proxy *proxy)
{
struct proxy_transaction *t;
struct proxy_tr *t;
struct client_tr *c;
auth_challenger_t _proxy_challenger[1] =
{{
......@@ -232,8 +284,6 @@ test_proxy_init(su_root_t *root, struct proxy *proxy)
proxy->root = root;
proxy->auth = auth_mod_create(root, TAG_NEXT(proxy->tags));
proxy->agent = nta_agent_create(root,
URL_STRING_MAKE("sip:0.0.0.0:*"),
NULL, NULL,
......@@ -247,53 +297,32 @@ test_proxy_init(su_root_t *root, struct proxy *proxy)
proxy->defleg = nta_leg_tcreate(proxy->agent,
proxy_request,
proxy,
(union proxy_or_domain *)proxy,
NTATAG_NO_DIALOG(1),
TAG_END());
proxy->example_net = nta_leg_tcreate(proxy->agent,
domain_request,
proxy,
NTATAG_NO_DIALOG(1),
URLTAG_URL("sip:example.net"),
TAG_END());
proxy->example_org = nta_leg_tcreate(proxy->agent,
domain_request,
proxy,
NTATAG_NO_DIALOG(1),
URLTAG_URL("sip:example.org"),
TAG_END());
proxy->example_com = nta_leg_tcreate(proxy->agent,
domain_request,
proxy,
NTATAG_NO_DIALOG(1),
URLTAG_URL("sip:example.com"),
TAG_END());
proxy->prefs.min_expires = 30;
proxy->prefs.expires = 3600;
proxy->prefs.max_expires = 3600;
proxy->prefs.session_expires = 180;
proxy->prefs.min_se = 90;
proxy->prefs.outbound_tcp = 1;
if (!proxy->defleg ||
!proxy->example_net || !proxy->example_org || !proxy->example_com)
if (!proxy->defleg)
return -1;
/* if (!proxy->example_net || !proxy->example_org || !proxy->example_com)
return -1; */
t = su_zalloc(proxy->home, sizeof *t);
/* Create stateless client */
t = su_zalloc(proxy->home, sizeof *t);
c = su_zalloc(proxy->home, sizeof *c);
if (!t)
if (!t || !c)
return -1;
proxy->stateless = t;
t->proxy = proxy;
c->t = t, client_tr_insert(&t->clients, c);
t->server = nta_incoming_default(proxy->agent);
t->client = nta_outgoing_default(proxy->agent, proxy_response, t);
c->client = nta_outgoing_default(proxy->agent, proxy_response, c);
if (!t->client || !t->server)
if (!c->client || !t->server)
return -1;
proxy->uri = nta_agent_contact(proxy->agent)->m_url;
......@@ -304,17 +333,15 @@ test_proxy_init(su_root_t *root, struct proxy *proxy)
static void
test_proxy_deinit(su_root_t *root, struct proxy *proxy)
{
struct proxy_transaction *t;
auth_mod_destroy(proxy->auth);
struct proxy_tr *t;
if ((t = proxy->stateless)) {
nta_incoming_destroy(t->server), t->server = NULL;
nta_outgoing_destroy(t->client), t->client = NULL;
proxy->stateless = NULL;
proxy_tr_destroy(t);
}
while (proxy->entries)
registration_entry_destroy(proxy->entries);
while (proxy->domains)
domain_destroy(proxy->domains);
nta_agent_destroy(proxy->agent);
......@@ -330,6 +357,8 @@ struct proxy *test_proxy_create(su_root_t *root,
if (p) {
ta_list ta;
p->magic = test_proxy_create;
p->parent = root;
ta_start(ta, tag, value);
......@@ -362,27 +391,27 @@ url_t const *test_proxy_uri(struct proxy const *p)
return p ? p->uri : NULL;
}
void test_proxy_set_expiration(struct proxy *p,
sip_time_t min_expires,
sip_time_t expires,
sip_time_t max_expires)
void test_proxy_domain_set_expiration(struct domain *d,
sip_time_t min_expires,
sip_time_t expires,
sip_time_t max_expires)
{
if (p) {
p->prefs.min_expires = min_expires;
p->prefs.expires = expires;
p->prefs.max_expires = max_expires;
if (d) {
d->prefs.min_expires = min_expires;
d->prefs.expires = expires;
d->prefs.max_expires = max_expires;
}
}
void test_proxy_get_expiration(struct proxy *p,
sip_time_t *return_min_expires,
sip_time_t *return_expires,
sip_time_t *return_max_expires)
void test_proxy_domain_get_expiration(struct domain *d,
sip_time_t *return_min_expires,
sip_time_t *return_expires,
sip_time_t *return_max_expires)
{
if (p) {
if (return_min_expires) *return_min_expires = p->prefs.min_expires;
if (return_expires) *return_expires = p->prefs.expires;
if (return_max_expires) *return_max_expires = p->prefs.max_expires;
if (d) {
if (return_min_expires) *return_min_expires = d->prefs.min_expires;
if (return_expires) *return_expires = d->prefs.expires;
if (return_max_expires) *return_max_expires = d->prefs.max_expires;
}
}
......@@ -407,20 +436,36 @@ void test_proxy_get_session_timer(struct proxy *p,
}
}
void test_proxy_set_outbound(struct proxy *p,
int use_outbound)
void test_proxy_domain_set_outbound(struct domain *d,
int use_outbound)
{
if (p) {
p->prefs.outbound_tcp = use_outbound;
if (d) {
d->prefs.outbound_tcp = use_outbound;
}
}
void test_proxy_get_outbound(struct proxy *p,
int *return_use_outbound)
void test_proxy_domain_get_outbound(struct domain *d,
int *return_use_outbound)
{
if (p) {
if (d) {
if (return_use_outbound)
*return_use_outbound = p->prefs.outbound_tcp;
*return_use_outbound = d->prefs.outbound_tcp;
}
}
void test_proxy_domain_set_authorize(struct domain *d, int authorize)
{
if (d) {
d->prefs.authorize = authorize;
}
}
void test_proxy_domain_get_authorize(struct domain *d,
int *return_authorize)
{
if (d) {
if (return_authorize)
*return_authorize = d->prefs.authorize;
}
}
......@@ -441,6 +486,106 @@ int test_proxy_close_tports(struct proxy *p)
/* ---------------------------------------------------------------------- */
struct domain *test_proxy_add_domain(struct proxy *p,
url_t const *uri,
tag_type_t tag, tag_value_t value, ...)
{
struct domain *d;
if (p == NULL || uri == NULL)
return NULL;
d = su_home_clone(p->home, sizeof *d);
if (d) {
ta_list ta;
int init = 0;
ta_start(ta, tag, value);
d->magic = domain_init;
d->proxy = p;
d->uri = url_hdup(d->home, uri);
d->tags = tl_adup(d->home, ta_args(ta));
d->prefs.min_expires = 300;
d->prefs.expires = 3600;
d->prefs.max_expires = 36000;
d->prefs.outbound_tcp = 0;
d->prefs.authorize = 0;
if (d->uri && d->tags &&
!su_task_execute(su_clone_task(p->clone), _domain_init, d, &init)) {
if (init == 0)
/* OK */;
else
d = NULL;
}
else
su_home_unref(d->home);
}
return d;
}
static int _domain_init(void *_d)
{
return domain_init(_d);
}
static int domain_init(struct domain *d)
{
struct proxy *p = d->proxy;
url_t uri[1];
*uri = *d->uri;
d->auth = auth_mod_create(p->root, TAG_NEXT(d->tags));
/* Leg for URIs without userpart */
d->rleg = nta_leg_tcreate(d->proxy->agent,
domain_request,
(union proxy_or_domain *)d,
NTATAG_NO_DIALOG(1),
URLTAG_URL(uri),
TAG_END());
/* Leg for URIs with wildcard userpart */
uri->url_user = "%";
d->uleg = nta_leg_tcreate(d->proxy->agent,
domain_request,
(union proxy_or_domain *)d,
NTATAG_NO_DIALOG(1),
URLTAG_URL(uri),
TAG_END());
if (d->auth && d->rleg && d->uleg) {
domain_insert(&p->domains, d);
return 0;
}
domain_destroy(d);
return -1;
}
static void domain_destroy(struct domain *d)
{
while (d->entries)
registration_entry_destroy(d->entries);
nta_leg_destroy(d->rleg), d->rleg = NULL;
nta_leg_destroy(d->uleg), d->uleg = NULL;
auth_mod_destroy(d->auth), d->auth = NULL;
domain_remove(d);
su_home_unref(d->home);
}
/* ---------------------------------------------------------------------- */
static sip_contact_t *create_transport_contacts(struct proxy *p)
{
su_home_t *home = p->home;
......@@ -474,166 +619,332 @@ static sip_contact_t *create_transport_contacts(struct proxy *p)
/* ---------------------------------------------------------------------- */
static int challenge_request(struct proxy *, nta_incoming_t *, sip_t const *);
static int proxy_tr_with(struct proxy *proxy,
struct domain *domain,
nta_incoming_t *irq,
sip_t const *sip,
int (*process)(struct proxy_tr *));
static int proxy_transaction(struct proxy_tr *t);
static int respond_transaction(struct proxy_tr *t,
int status, char const *phrase,
tag_type_t tag, tag_value_t value,
...);
static int validate_transaction(struct proxy_tr *t);
static int originating_transaction(struct proxy_tr *t);
static int challenge_transaction(struct proxy_tr *t);
static int session_timers(struct proxy_tr *t);
static int incoming_transaction(struct proxy_tr *t);
static int target_transaction(struct proxy_tr *t,
url_t const *target,
tport_t *tport);
static int process_register(struct proxy_tr *t);
static int process_options(struct proxy_tr *t);
static int proxy_ack_cancel(struct proxy_tr *t,
nta_incoming_t *irq,
sip_t const *sip);
/** Forward request */
static
int proxy_request(struct proxy *proxy,
nta_leg_t *leg,
nta_incoming_t *irq,
sip_t const *sip)
static struct registration_entry *
registration_entry_find(struct domain const *domain, url_t const *uri);
static int proxy_request(union proxy_or_domain *pod,
nta_leg_t *leg,
nta_incoming_t *irq,
sip_t const *sip)
{
url_t const *request_uri, *target;
struct proxy_transaction *t = NULL;
sip_request_t *rq = NULL;
sip_max_forwards_t *mf;
assert(pod->proxy->magic = test_proxy_init);
return proxy_tr_with(pod->proxy, NULL, irq, sip, proxy_transaction);
}
static int domain_request(union proxy_or_domain *pod,
nta_leg_t *leg,
nta_incoming_t *irq,
sip_t const *sip)
{
int (*process)(struct proxy_tr *) = NULL;
sip_method_t method = sip->sip_request->rq_method;
sip_session_expires_t *x = NULL, x0[1];
sip_min_se_t *min_se = NULL, min_se0[1];
char const *require = NULL;
tport_t *tport = NULL;
assert(pod->domain->magic = domain_init);
if (leg == pod->domain->uleg)
process = proxy_transaction;
else if (method == sip_method_register)
process = process_register;
else if (method == sip_method_options)
process = process_options;
if (process == NULL)
return 501; /* Not implemented */
return proxy_tr_with(pod->domain->proxy, pod->domain, irq, sip, process);
}
static int proxy_tr_with(struct proxy *proxy,
struct domain *domain,
nta_incoming_t *irq,