📄 test_proxy.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE test_proxy.c * @brief Extremely simple proxy and registrar for testing nua * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Thu Nov 3 22:49:46 EET 2005 */#include "config.h"#include <string.h>struct proxy;struct proxy_transaction;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#include <sofia-sip/su_wait.h>#include <sofia-sip/nta.h>#include <sofia-sip/sip_header.h>#include <sofia-sip/sip_status.h>#include <sofia-sip/sip_util.h>#include <sofia-sip/auth_module.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/msg_addr.h>#include <stdlib.h>#include <assert.h>#define LIST_PROTOS(STORAGE, PREFIX, T) \STORAGE void PREFIX ##_insert(T **list, T *node), \ PREFIX ##_remove(T *node) #define LIST_BODIES(STORAGE, PREFIX, T, NEXT, PREV) \STORAGE void PREFIX ##_insert(T **list, T *node) \{ \ if ((node->NEXT = *list)) { \ node->PREV = node->NEXT->PREV; \ node->NEXT->PREV = &node->NEXT; \ } \ else \ node->PREV = list; \ *list = node; \} \STORAGE void PREFIX ##_remove(T *node) \{ \ if (node->PREV) \ if ((*node->PREV = node->NEXT)) \ node->NEXT->PREV = node->PREV; \ node->PREV = NULL; \} \extern int LIST_DUMMY_VARIABLE#include <test_proxy.h>struct proxy { su_home_t home[1]; 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; nta_leg_t *example_net; nta_leg_t *example_org; nta_leg_t *example_com; sip_contact_t *transport_contacts; struct proxy_transaction *stateless; struct proxy_transaction *transactions; struct registration_entry *entries; struct { sip_time_t min_expires, expires, max_expires; } prefs;}; LIST_PROTOS(static, registration_entry, struct registration_entry);static struct registration_entry *registration_entry_new(struct proxy *, url_t const *);static void registration_entry_destroy(struct registration_entry *e);struct registration_entry{ struct registration_entry *next, **prev; struct proxy *proxy; /* backpointer */ url_t *aor; /* address-of-record */ struct binding *bindings; /* list of bindings */ sip_contact_t *contacts;};struct binding{ struct binding *next, **prev; sip_contact_t *contact; /* bindings */ sip_time_t registered, expires; /* When registered and when expires */ sip_call_id_t *call_id; uint32_t cseq;};static struct binding *binding_new(su_home_t *home, sip_contact_t *contact, sip_call_id_t *call_id, uint32_t cseq, sip_time_t registered, sip_time_t expires);static void binding_destroy(su_home_t *home, struct binding *b);static int binding_is_active(struct binding const *b){ return b->expires > sip_now();}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);struct proxy_transaction{ struct proxy_transaction *next, **prev; struct proxy *proxy; /* backpointer */ sip_request_t *rq; /* request line */ nta_incoming_t *server; /* server transaction */ nta_outgoing_t *client; /* client transaction */};static sip_contact_t *create_transport_contacts(struct proxy *p);static int proxy_request(struct proxy *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, nta_leg_t *leg, nta_incoming_t *irq, sip_t const *sip);static int process_options(struct proxy *proxy, nta_incoming_t *irq, sip_t const *sip);static struct registration_entry *registration_entry_find(struct proxy const *proxy, url_t const *uri);static auth_challenger_t registrar_challenger[1];static auth_challenger_t proxy_challenger[1];/* Proxy entry point */static int test_proxy_init(su_root_t *root, struct proxy *proxy){ struct proxy_transaction *t; auth_challenger_t _proxy_challenger[1] = {{ SIP_407_PROXY_AUTH_REQUIRED, sip_proxy_authenticate_class, sip_proxy_authentication_info_class }}; auth_challenger_t _registrar_challenger[1] = {{ SIP_401_UNAUTHORIZED, sip_www_authenticate_class, sip_authentication_info_class }}; *proxy_challenger = *_proxy_challenger; *registrar_challenger = *_registrar_challenger; 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, NTATAG_UA(0), NTATAG_SERVER_RPORT(1), NTATAG_CLIENT_RPORT(1), TAG_END()); proxy->transport_contacts = create_transport_contacts(proxy); proxy->defleg = nta_leg_tcreate(proxy->agent, proxy_request, 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; if (!proxy->defleg || !proxy->example_net || !proxy->example_org || !proxy->example_com) return -1; t = su_zalloc(proxy->home, sizeof *t); if (!t) return -1; proxy->stateless = t; t->proxy = proxy; t->server = nta_incoming_default(proxy->agent); t->client = nta_outgoing_default(proxy->agent, proxy_response, t); if (!t->client || !t->server) return -1; proxy->uri = nta_agent_contact(proxy->agent)->m_url; return 0;}static voidtest_proxy_deinit(su_root_t *root, struct proxy *proxy){ struct proxy_transaction *t; auth_mod_destroy(proxy->auth); if ((t = proxy->stateless)) { nta_incoming_destroy(t->server), t->server = NULL; nta_outgoing_destroy(t->client), t->client = NULL; } nta_agent_destroy(proxy->agent); while (proxy->entries) registration_entry_destroy(proxy->entries); free(proxy->tags);}/* Create tst proxy object */struct proxy *test_proxy_create(su_root_t *root, tag_type_t tag, tag_value_t value, ...){ struct proxy *p = su_home_new(sizeof *p); if (p) { ta_list ta; p->parent = root; ta_start(ta, tag, value); p->tags = tl_llist(ta_tags(ta)); ta_end(ta); if (su_clone_start(root, p->clone, p, test_proxy_init, test_proxy_deinit) == -1) su_home_unref(p->home), p = NULL; } return p;}/* Destroy the proxy object */void test_proxy_destroy(struct proxy *p){ if (p) { su_clone_wait(p->parent, p->clone); su_home_unref(p->home); }}/* Return the proxy URI */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){ if (p) { p->prefs.min_expires = min_expires; p->prefs.expires = expires; p->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){ 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; }}/* ---------------------------------------------------------------------- */static sip_contact_t *create_transport_contacts(struct proxy *p){ su_home_t *home = p->home; sip_via_t *v; sip_contact_t *retval = NULL, **mm = &retval; if (!p->agent) return NULL; for (v = nta_agent_via(p->agent); v; v = v->v_next) { char const *proto = v->v_protocol; if (v->v_next && strcasecmp(v->v_host, v->v_next->v_host) == 0 && str0cmp(v->v_port, v->v_next->v_port) == 0 && ((proto == sip_transport_udp && v->v_next->v_protocol == sip_transport_tcp) || (proto == sip_transport_tcp && v->v_next->v_protocol == sip_transport_udp))) /* We have udp/tcp pair, insert URL without tport parameter */ *mm = sip_contact_create_from_via_with_transport(home, v, NULL, NULL); if (*mm) mm = &(*mm)->m_next; *mm = sip_contact_create_from_via_with_transport(home, v, NULL, proto); if (*mm) mm = &(*mm)->m_next; } return retval;}/* ---------------------------------------------------------------------- */static int challenge_request(struct proxy *, nta_incoming_t *, sip_t const *);/** Forward request */staticint proxy_request(struct proxy *proxy, 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; sip_method_t method = sip->sip_request->rq_method; mf = sip->sip_max_forwards; if (mf && mf->mf_count <= 1) { if (sip->sip_request->rq_method == sip_method_options) { return process_options(proxy, irq, sip); } nta_incoming_treply(irq, SIP_483_TOO_MANY_HOPS, TAG_END()); return 483; } if (method != sip_method_ack && method != sip_method_cancel && str0casecmp(sip->sip_from->a_url->url_host, "example.net") == 0) { /* Challenge everything but CANCEL and ACK coming from Mr. C */ int status = challenge_request(proxy, irq, sip); if (status) return status; } /* We don't do any route processing */ request_uri = sip->sip_request->rq_url; if (!request_uri->url_host || (strcasecmp(request_uri->url_host, "example.org") && strcasecmp(request_uri->url_host, "example.net") && strcasecmp(request_uri->url_host, "example.com"))) { target = request_uri; } else { struct registration_entry *e; struct binding *b; if (sip->sip_request->rq_method == sip_method_register) return process_register(proxy, irq, sip); e = registration_entry_find(proxy, request_uri); if (e == NULL) { nta_incoming_treply(irq, SIP_404_NOT_FOUND, TAG_END()); return 404; } for (b = e->bindings; b; b = b->next) if (binding_is_active(b)) break; if (b == NULL) { nta_incoming_treply(irq, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END()); return 480; } target = b->contact->m_url; } t = proxy_transaction_new(proxy); if (t == NULL) { nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); return 500; } nta_incoming_bind(t->server = irq, proxy_ack_cancel, t); rq = sip_request_create(proxy->home, sip->sip_request->rq_method, sip->sip_request->rq_method_name, (url_string_t *)target, NULL); if (rq == NULL) { nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); proxy_transaction_destroy(t); return 500; } t->rq = rq; /* Forward request */ t->client = nta_outgoing_mcreate(proxy->agent, proxy_response, t, NULL, nta_incoming_getrequest(irq), /* rewrite request */ SIPTAG_REQUEST(rq), TAG_END()); if (t->client == NULL) { proxy_transaction_destroy(t); nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END()); return 500; } else if (sip->sip_request->rq_method == sip_method_ack) proxy_transaction_destroy(t); return 0;}staticint challenge_request(struct proxy *p, nta_incoming_t *irq, sip_t const *sip){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -