diff options
author | Corey Farrell <git@cfware.com> | 2014-02-10 18:28:35 +0000 |
---|---|---|
committer | Corey Farrell <git@cfware.com> | 2014-02-10 18:28:35 +0000 |
commit | cb4e2107735dc05c1ad96b6a955c056e06b8dc1c (patch) | |
tree | 7200a261115a632a38ae4f12049359ee061cc4ee /channels/sip | |
parent | 72bf9b13150f50198a302c365c6c3274d38c2ebc (diff) |
chan_sip: Isolate code that manages struct sip_route.
* Move route code to sip/route.c + sip/include/route.h
* Rename functions to sip_route_*
* Replace ad-hoc list code with macro's from linkedlists.h
* Create sip_route_process_header() to processes Path and Record-Route headers
(previously done with different code in build_route and build_path)
* Add use of const where possible
* Move struct uriparams, struct contact and contactliststruct from sip.h to
reqresp_parser.h. sip/route.c uses reqresp_parser.h but not sip.h, this was
a problem. These moved declares are not used outside of reqresp_parser.
* While modifying reqprep() the lack of {} caused me trouble. I added them.
* Code outside route.c treats sip_route as an opaque structure, using macro's
or procedures for all access.
(closes issue ASTERISK-22582)
Reported by: Corey Farrell
Review: https://reviewboard.asterisk.org/r/3173/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@407926 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'channels/sip')
-rw-r--r-- | channels/sip/include/reqresp_parser.h | 24 | ||||
-rw-r--r-- | channels/sip/include/route.h | 120 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 40 | ||||
-rw-r--r-- | channels/sip/route.c | 205 |
4 files changed, 353 insertions, 36 deletions
diff --git a/channels/sip/include/reqresp_parser.h b/channels/sip/include/reqresp_parser.h index 02b046bc7..7f9c8f6d9 100644 --- a/channels/sip/include/reqresp_parser.h +++ b/channels/sip/include/reqresp_parser.h @@ -22,6 +22,30 @@ #ifndef _SIP_REQRESP_H #define _SIP_REQRESP_H +/*! \brief uri parameters */ +struct uriparams { + char *transport; + char *user; + char *method; + char *ttl; + char *maddr; + int lr; +}; + +struct contact { + AST_LIST_ENTRY(contact) list; + char *name; + char *user; + char *pass; + char *hostport; + struct uriparams params; + char *headers; + char *expires; + char *q; +}; + +AST_LIST_HEAD_NOLOCK(contactliststruct, contact); + /*! * \brief parses a URI in its components. * diff --git a/channels/sip/include/route.h b/channels/sip/include/route.h new file mode 100644 index 000000000..511f0ff53 --- /dev/null +++ b/channels/sip/include/route.h @@ -0,0 +1,120 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013, Digium, Inc. + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief sip_route header file + */ + +#ifndef _SIP_ROUTE_H +#define _SIP_ROUTE_H + +#include "asterisk/linkedlists.h" +#include "asterisk/strings.h" + +/*! + * \brief Opaque storage of a sip route hop + */ +struct sip_route_hop; + +/*! + * \internal \brief Internal enum to remember last calculated + */ +enum sip_route_type { + route_loose = 0, /*!< The first hop contains ;lr or does not exist */ + route_strict, /*!< The first hop exists and does not contain ;lr */ + route_invalidated, /*!< strict/loose routing needs to be rechecked */ +}; + +/*! + * \brief Structure to store route information + * + * \note This must be zero-filled on allocation + */ +struct sip_route { + AST_LIST_HEAD_NOLOCK(, sip_route_hop) list; + enum sip_route_type type; +}; + +/*! + * \brief Add a new hop to the route + * + * \param route Route + * \param uri Address of this hop + * \param len Length of hop not including null terminator + * \param inserthead If true then inserted the new route to the top of the list + * + * \retval Pointer to null terminated copy of URI on success + * \retval NULL on error + */ +const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead); + +/*! + * \brief Add routes from header + * + * \note This procedure is for headers that require use of <brackets>. + */ +void sip_route_process_header(struct sip_route *route, const char *header, int inserthead); + +/*! + * \brief copy route-set + * + * \retval non-zero on failure + * \retval 0 on success + */ +void sip_route_copy(struct sip_route *dst, const struct sip_route *src); + +/*! + * \brief Free all routes in the list + */ +void sip_route_clear(struct sip_route *route); + +/*! + * \brief Verbose dump of all hops for debugging + */ +void sip_route_dump(const struct sip_route *route); + +/*! + * \brief Make the comma separated list of route hops + * + * \param route Source of route list + * \param formatcli Add's space after comma's, print's N/A if list is empty. + * \param skip Number of hops to skip + * + * \retval an allocated struct ast_str on success + * \retval NULL on failure + */ +struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip) + __attribute_malloc__ __attribute_warn_unused_result__; + +/*! + * \brief Check if the route is strict + * + * \note The result is cached in route->type + */ +int sip_route_is_strict(struct sip_route *route); + +/*! + * \brief Get the URI of the route's first hop + */ +const char *sip_route_first_uri(const struct sip_route *route); + +/*! + * \brief Check if route has no URI's + */ +#define sip_route_empty(route) AST_LIST_EMPTY(&(route)->list) + +#endif diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index 0b88dae43..7e2d0b960 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -39,6 +39,8 @@ #include "asterisk/netsock2.h" #include "asterisk/features_config.h" +#include "route.h" + #ifndef FALSE #define FALSE 0 #endif @@ -847,12 +849,6 @@ struct sip_invite_param { struct sip_proxy *outboundproxy; /*!< Outbound proxy URI */ }; -/*! \brief Structure to save routing information for a SIP session */ -struct sip_route { - struct sip_route *next; - char hop[0]; -}; - /*! \brief Structure to store Via information */ struct sip_via { char *via; @@ -1119,7 +1115,7 @@ struct sip_pvt { struct ast_sockaddr ourip; /*!< Our IP (as seen from the outside) */ enum transfermodes allowtransfer; /*!< REFER: restriction scheme */ struct ast_channel *owner; /*!< Who owns us (if we have an owner) */ - struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */ + struct sip_route route; /*!< List of routing steps (fm Record-Route) */ struct sip_notify *notify; /*!< Custom notify type */ struct sip_auth_container *peerauth;/*!< Realm authentication credentials */ int noncecount; /*!< Nonce-count */ @@ -1346,7 +1342,7 @@ struct sip_peer { int timer_t1; /*!< The maximum T1 value for the peer */ int timer_b; /*!< The maximum timer B (transaction timeouts) */ int fromdomainport; /*!< The From: domain port */ - struct sip_route *path; /*!< Head of linked list of out-of-dialog outgoing routing steps (fm Path headers) */ + struct sip_route path; /*!< List of out-of-dialog outgoing routing steps (fm Path headers) */ /*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */ enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */ @@ -1804,34 +1800,6 @@ struct sip_monitor_instance { struct sip_epa_entry *suspension_entry; }; -/*! - * \brief uri parameters - * - */ - -struct uriparams { - char *transport; - char *user; - char *method; - char *ttl; - char *maddr; - int lr; -}; - -struct contact { - AST_LIST_ENTRY(contact) list; - char *name; - char *user; - char *pass; - char *hostport; - struct uriparams params; - char *headers; - char *expires; - char *q; -}; - -AST_LIST_HEAD_NOLOCK(contactliststruct, contact); - /*! \brief List of well-known SIP options. If we get this in a require, we should check the list and answer accordingly. */ static const struct cfsip_options { diff --git a/channels/sip/route.c b/channels/sip/route.c new file mode 100644 index 000000000..5f0d62e5c --- /dev/null +++ b/channels/sip/route.c @@ -0,0 +1,205 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2013, Digium, Inc. + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! + * \file + * \brief sip_route functions + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/utils.h" + +#include "include/route.h" +#include "include/reqresp_parser.h" + +/*! + * \brief Traverse route hops + */ +#define sip_route_traverse(route,elem) AST_LIST_TRAVERSE(&(route)->list, elem, list) +#define sip_route_first(route) AST_LIST_FIRST(&(route)->list) + +/*! + * \brief Structure to save a route hop + */ +struct sip_route_hop { + AST_LIST_ENTRY(sip_route_hop) list; + char uri[0]; +}; + +const char *sip_route_add(struct sip_route *route, const char *uri, size_t len, int inserthead) +{ + struct sip_route_hop *hop; + + if (!uri || len < 1 || uri[0] == '\0') { + return NULL; + } + + /* Expand len to include null terminator */ + len++; + + /* ast_calloc is not needed because all fields are initialized in this block */ + hop = ast_malloc(sizeof(struct sip_route_hop) + len); + if (!hop) { + return NULL; + } + ast_copy_string(hop->uri, uri, len); + + if (inserthead) { + AST_LIST_INSERT_HEAD(&route->list, hop, list); + route->type = route_invalidated; + } else { + if (sip_route_empty(route)) { + route->type = route_invalidated; + } + AST_LIST_INSERT_TAIL(&route->list, hop, list); + hop->list.next = NULL; + } + + return hop->uri; +} + +void sip_route_process_header(struct sip_route *route, const char *header, int inserthead) +{ + const char *hop; + int len = 0; + const char *uri; + + if (!route) { + ast_log(LOG_ERROR, "sip_route_process_header requires non-null route"); + ast_do_crash(); + return; + } + + while (!get_in_brackets_const(header, &uri, &len)) { + header = strchr(header, ','); + if (header >= uri && header <= (uri + len)) { + /* comma inside brackets */ + const char *next_br = strchr(header, '<'); + if (next_br && next_br <= (uri + len)) { + header++; + continue; + } + continue; + } + if ((hop = sip_route_add(route, uri, len, inserthead))) { + ast_debug(2, "sip_route_process_header: <%s>\n", hop); + } + header = strchr(uri + len + 1, ','); + if (header == NULL) { + /* No more field-values, we're done with this header */ + break; + } + /* Advance past comma */ + header++; + } +} + +void sip_route_copy(struct sip_route *dst, const struct sip_route *src) +{ + struct sip_route_hop *hop; + + /* make sure dst is empty */ + sip_route_clear(dst); + + sip_route_traverse(src, hop) { + const char *uri = sip_route_add(dst, hop->uri, strlen(hop->uri), 0); + if (uri) { + ast_debug(2, "sip_route_copy: copied hop: <%s>\n", uri); + } + } + + dst->type = src->type; +} + +void sip_route_clear(struct sip_route *route) +{ + struct sip_route_hop *hop; + + while ((hop = AST_LIST_REMOVE_HEAD(&route->list, list))) { + ast_free(hop); + } + + route->type = route_loose; +} + +void sip_route_dump(const struct sip_route *route) +{ + if (sip_route_empty(route)) { + ast_verbose("sip_route_dump: no route/path\n"); + } else { + struct sip_route_hop *hop; + sip_route_traverse(route, hop) { + ast_verbose("sip_route_dump: route/path hop: <%s>\n", hop->uri); + } + } +} + +struct ast_str *sip_route_list(const struct sip_route *route, int formatcli, int skip) +{ + struct sip_route_hop *hop; + const char *comma; + struct ast_str *buf; + int i = 0 - skip; + + buf = ast_str_create(64); + if (!buf) { + return NULL; + } + + comma = formatcli ? ", " : ","; + + sip_route_traverse(route, hop) { + if (i >= 0) { + ast_str_append(&buf, 0, "%s<%s>", i ? comma : "", hop->uri); + } + i++; + } + + if (formatcli && i <= 0) { + ast_str_append(&buf, 0, "N/A"); + } + + return buf; +} + +int sip_route_is_strict(struct sip_route *route) +{ + if (!route) { + return 0; + } + + if (route->type == route_invalidated) { + struct sip_route_hop *hop = sip_route_first(route); + int ret = hop && (strstr(hop->uri, ";lr") == NULL); + route->type = ret ? route_strict : route_loose; + return ret; + } + + return (route->type == route_strict) ? 1 : 0; +} + +const char *sip_route_first_uri(const struct sip_route *route) +{ + struct sip_route_hop *hop = sip_route_first(route); + return hop ? hop->uri : NULL; +} |