Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
}
static struct sip_esc_entry *get_esc_entry(const char * entity_tag, struct event_state_compositor *esc) {
struct sip_esc_entry *entry;
struct sip_esc_entry finder;
ast_copy_string(finder.entity_tag, entity_tag, sizeof(finder.entity_tag));
entry = ao2_find(esc->compositor, &finder, OBJ_POINTER);
return entry;
}
static int publish_expire(const void *data)
{
struct sip_esc_entry *esc_entry = (struct sip_esc_entry *) data;
struct event_state_compositor *esc = get_esc(esc_entry->event);
ast_assert(esc != NULL);
ao2_unlink(esc->compositor, esc_entry);
ao2_ref(esc_entry, -1);
return 0;
}
static void create_new_sip_etag(struct sip_esc_entry *esc_entry, int is_linked)
{
int new_etag = ast_atomic_fetchadd_int(&esc_etag_counter, +1);
struct event_state_compositor *esc = get_esc(esc_entry->event);
ast_assert(esc != NULL);
if (is_linked) {
ao2_unlink(esc->compositor, esc_entry);
}
snprintf(esc_entry->entity_tag, sizeof(esc_entry->entity_tag), "%d", new_etag);
ao2_link(esc->compositor, esc_entry);
}
static struct sip_esc_entry *create_esc_entry(struct event_state_compositor *esc, struct sip_request *req, const int expires)
{
struct sip_esc_entry *esc_entry;
int expires_ms;
if (!(esc_entry = ao2_alloc(sizeof(*esc_entry), esc_entry_destructor))) {
return NULL;
}
esc_entry->event = esc->name;
expires_ms = expires * 1000;
/* Bump refcount for scheduler */
ao2_ref(esc_entry, +1);
esc_entry->sched_id = ast_sched_add(sched, expires_ms, publish_expire, esc_entry);
/* Note: This links the esc_entry into the ESC properly */
create_new_sip_etag(esc_entry, 0);
return esc_entry;
}
static int initialize_escs(void)
{
int i, res = 0;
for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
if (!((event_state_compositors[i].compositor) =
ao2_container_alloc(ESC_MAX_BUCKETS, esc_hash_fn, esc_cmp_fn))) {
res = -1;
}
}
return res;
}
static void destroy_escs(void)
{
int i;
for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
ao2_ref(event_state_compositors[i].compositor, -1);
}
}
/*!
* \details
Stefan Schmidt
committed
* Here we implement the container for dialogs which are in the
* dialog_needdestroy state to iterate only through the dialogs
* unlink them instead of iterate through all dialogs
*/
struct ao2_container *dialogs_needdestroy;
/*!
* \details
Stefan Schmidt
committed
* Here we implement the container for dialogs which have rtp
* traffic and rtptimeout, rtpholdtimeout or rtpkeepalive
* set. We use this container instead the whole dialog list.
*/
struct ao2_container *dialogs_rtpcheck;
/*!
* \details
* Here we implement the container for dialogs (sip_pvt), defining
* generic wrapper functions to ease the transition from the current
* implementation (a single linked list) to a different container.
* In addition to a reference to the container, we need functions to lock/unlock
* the container and individual items, and functions to add/remove
* references to the individual items.
*/
static struct ao2_container *dialogs;
#define sip_pvt_lock(x) ao2_lock(x)
#define sip_pvt_trylock(x) ao2_trylock(x)
#define sip_pvt_unlock(x) ao2_unlock(x)
/*! \brief The table of TCP threads */
static struct ao2_container *threadt;
/*! \brief The peer list: Users, Peers and Friends */
static struct ao2_container *peers;
static struct ao2_container *peers_by_ip;
/*! \brief The register list: Other SIP proxies we register with and receive calls from */
static struct ast_register_list {
Mark Spencer
committed
ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
/*! \brief The MWI subscription list */
static struct ast_subscription_mwi_list {
ASTOBJ_CONTAINER_COMPONENTS(struct sip_subscription_mwi);
} submwil;
Kevin P. Fleming
committed
static int temp_pvt_init(void *);
Russell Bryant
committed
static void temp_pvt_cleanup(void *);
/*! \brief A per-thread temporary pvt structure */
Kevin P. Fleming
committed
AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup);
/*! \brief Authentication container for realm authentication */
static struct sip_auth_container *authl = NULL;
/*! \brief Global authentication container protection while adjusting the references. */
AST_MUTEX_DEFINE_STATIC(authl_lock);
/* --- Sockets and networking --------------*/
Olle Johansson
committed
/*! \brief Main socket for UDP SIP communication.
*
* sipsock is shared between the SIP manager thread (which handles reload
Olle Johansson
committed
* requests), the udp io handler (sipsock_read()) and the user routines that
* issue udp writes (using __sip_xmit()).
* The socket is -1 only when opening fails (this is a permanent condition),
* or when we are handling a reload() that changes its address (this is
* a transient situation during which we might have a harmless race, see
* below). Because the conditions for the race to be possible are extremely
* rare, we don't want to pay the cost of locking on every I/O.
* Rather, we remember that when the race may occur, communication is
* bound to fail anyways, so we just live with this event and let
* the protocol handle this above us.
*/
static int sipsock = -1;
struct ast_sockaddr bindaddr; /*!< UDP: The address we bind to */
/*! \brief our (internal) default address/port to put in SIP/SDP messages
* internip is initialized picking a suitable address from one of the
* interfaces, and the same port number we bind to. It is used as the
* default address/port in SIP messages, and as the default address
* (but not port) in SDP messages.
*/
/*! \brief our external IP address/port for SIP sessions.
* externaddr.sin_addr is only set when we know we might be behind
* a NAT, and this is done using a variety of (mutually exclusive)
* ways from the config file:
*
* + with "externaddr = host[:port]" we specify the address/port explicitly.
* The address is looked up only once when (re)loading the config file;
* + with "externhost = host[:port]" we do a similar thing, but the
* hostname is stored in externhost, and the hostname->IP mapping
* is refreshed every 'externrefresh' seconds;
* Other variables (externhost, externexpire, externrefresh) are used
* to support the above functions.
*/
static struct ast_sockaddr externaddr; /*!< External IP address if we are behind NAT */
static struct ast_sockaddr media_address; /*!< External RTP IP address if we are behind NAT */
static char externhost[MAXHOSTNAMELEN]; /*!< External host name */
static time_t externexpire; /*!< Expiration counter for re-resolving external host name in dynamic DNS */
static int externrefresh = 10; /*!< Refresh timer for DNS-based external address (dyndns) */
static uint16_t externtcpport; /*!< external tcp port */
static uint16_t externtlsport; /*!< external tls port */
/*! \brief List of local networks
* We store "localnet" addresses from the config file into an access list,
* marked as 'DENY', so the call to ast_apply_ha() will return
* AST_SENSE_DENY for 'local' addresses, and AST_SENSE_ALLOW for 'non local'
* (i.e. presumably public) addresses.
*/
static struct ast_ha *localaddr; /*!< List of local networks, on the same side of NAT as this Asterisk */
static int ourport_tcp; /*!< The port used for TCP connections */
static int ourport_tls; /*!< The port used for TCP/TLS connections */
static struct ast_config *notify_types = NULL; /*!< The list of manual NOTIFY types we know how to send */
/*! some list management macros. */
#define UNLINK(element, head, prev) do { \
if (prev) \
(prev)->next = (element)->next; \
else \
(head) = (element)->next; \
} while (0)
Olle Johansson
committed
/*---------------------------- Forward declarations of functions in chan_sip.c */
/* Note: This is added to help splitting up chan_sip.c into several files
in coming releases. */
Olle Johansson
committed
/*--- PBX interface functions */
static struct ast_channel *sip_request_call(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause);
Olle Johansson
committed
static int sip_devicestate(void *data);
static int sip_sendtext(struct ast_channel *ast, const char *text);
static int sip_call(struct ast_channel *ast, char *dest, int timeout);
static int sip_sendhtml(struct ast_channel *chan, int subclass, const char *data, int datalen);
Olle Johansson
committed
static int sip_hangup(struct ast_channel *ast);
static int sip_answer(struct ast_channel *ast);
static struct ast_frame *sip_read(struct ast_channel *ast);
static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
static int sip_transfer(struct ast_channel *ast, const char *dest);
static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int sip_senddigit_begin(struct ast_channel *ast, char digit);
static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen);
Joshua Colp
committed
static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
static const char *sip_get_callid(struct ast_channel *chan);
static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr);
static int sip_standard_port(enum sip_transport type, int port);
static int sip_prepare_socket(struct sip_pvt *p);
static int get_address_family_filter(const struct ast_sockaddr *addr);
Olle Johansson
committed
/*--- Transmitting responses and requests */
static int sipsock_read(int *id, int fd, short events, void *ignore);
static int __sip_xmit(struct sip_pvt *p, struct ast_str *data);
static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int fatal, int sipmethod);
static void add_cc_call_info_to_response(struct sip_pvt *p, struct sip_request *resp);
static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
static int retrans_pkt(const void *data);
static int transmit_response_using_temp(ast_string_field callid, struct ast_sockaddr *addr, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg);
static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
Mark Michelson
committed
static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid);
static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
static int transmit_provisional_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, int with_sdp);
static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable);
static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_type publish_type, const char * const explicit_uri);
static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init, const char * const explicit_uri);
Russell Bryant
committed
static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int oldsdp);
static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded);
static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
static int transmit_info_with_vidupdate(struct sip_pvt *p);
static int transmit_message_with_text(struct sip_pvt *p, const char *text, int init, int auth);
static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *msg);
Mark Spencer
committed
static int transmit_refer(struct sip_pvt *p, const char *dest);
static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten);
static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
static int transmit_cc_notify(struct ast_cc_agent *agent, struct sip_pvt *subscription, enum sip_cc_notify_state state);
static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader);
Olle Johansson
committed
static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
static void copy_request(struct sip_request *dst, const struct sip_request *src);
static void receive_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
Mark Michelson
committed
static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward);
static int sip_send_mwi_to_peer(struct sip_peer *peer, int cache_only);
Olle Johansson
committed
Tilghman Lesher
committed
/* Misc dialog routines */
static int __sip_autodestruct(const void *data);
static void *registry_unref(struct sip_registry *reg, char *tag);
Olle Johansson
committed
static int update_call_counter(struct sip_pvt *fup, int event);
Tilghman Lesher
committed
static int auto_congest(const void *arg);
static struct sip_pvt *find_call(struct sip_request *req, struct ast_sockaddr *addr, const int intended_method);
static void free_old_route(struct sip_route *route);
static void list_route(struct sip_route *route);
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards);
static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
struct sip_request *req, const char *uri);
static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
static void check_pendings(struct sip_pvt *p);
static void *sip_park_thread(void *stuff);
static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, const char *park_exten, const char *park_context);
static void *sip_pickup_thread(void *stuff);
static int sip_pickup(struct ast_channel *chan);
static int sip_sipredirect(struct sip_pvt *p, const char *dest);
Olle Johansson
committed
static int is_method_allowed(unsigned int *allowed_methods, enum sipmethod method);
Olle Johansson
committed
/*--- Codec handling / SDP */
static void try_suggested_sip_codec(struct sip_pvt *p);
Matthew Nicholson
committed
static const char *get_sdp_iterate(int* start, struct sip_request *req, const char *name);
static char get_sdp_line(int *start, int stop, struct sip_request *req, const char **value);
static int find_sdp(struct sip_request *req);
static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action);
Matthew Nicholson
committed
static int process_sdp_o(const char *o, struct sip_pvt *p);
static int process_sdp_c(const char *c, struct ast_sockaddr *addr);
Matthew Nicholson
committed
static int process_sdp_a_sendonly(const char *a, int *sendonly);
static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec);
static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec);
static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newtextrtp, char *red_fmtp, int *red_num_gen, int *red_data_pt, int *last_rtpmap_codec);
static int process_sdp_a_image(const char *a, struct sip_pvt *p);
static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
struct ast_str **m_buf, struct ast_str **a_buf,
int debug, int *min_packet_size);
Kevin P. Fleming
committed
static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
struct ast_str **m_buf, struct ast_str **a_buf,
Olle Johansson
committed
int debug);
static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38);
static void do_setnat(struct sip_pvt *p);
static void stop_media_flows(struct sip_pvt *p);
Olle Johansson
committed
/*--- Authentication stuff */
static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, int sipmethod, char *digest, int digest_len);
static int build_reply_digest(struct sip_pvt *p, int method, char *digest, int digest_len);
static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
const char *secret, const char *md5secret, int sipmethod,
const char *uri, enum xmittype reliable, int ignore);
static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
int sipmethod, const char *uri, enum xmittype reliable,
struct ast_sockaddr *addr, struct sip_peer **authpeer);
static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct ast_sockaddr *addr);
Olle Johansson
committed
/*--- Domain handling */
static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
static int add_sip_domain(const char *domain, const enum domain_mode mode, const char *context);
static void clear_sip_domains(void);
Olle Johansson
committed
/*--- SIP realm authentication */
static void add_realm_authentication(struct sip_auth_container **credentials, const char *configuration, int lineno);
static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm);
Olle Johansson
committed
/*--- Misc functions */
static int check_rtp_timeout(struct sip_pvt *dialog, time_t t);
static int reload_config(enum channelreloadreason reason);
static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt);
static int expire_register(const void *data);
static void *do_monitor(void *data);
Olle Johansson
committed
static int restart_monitor(void);
Tilghman Lesher
committed
static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer);
Olle Johansson
committed
static struct ast_variable *copy_vars(struct ast_variable *src);
static int dialog_find_multiple(void *obj, void *arg, int flags);
static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt);
/* static int sip_addrcmp(char *name, struct sockaddr_in *sin); Support for peer matching */
static int sip_refer_allocate(struct sip_pvt *p);
static int sip_notify_allocate(struct sip_pvt *p);
static void ast_quiet_chan(struct ast_channel *chan);
static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
Olle Johansson
committed
/*--- Device monitoring and Device/extension state/event handling */
static int cb_extensionstate(const char *context, const char *exten, enum ast_extension_states state, void *data);
static int sip_devicestate(void *data);
static int sip_poke_noanswer(const void *data);
static int sip_poke_peer(struct sip_peer *peer, int force);
static void sip_poke_all_peers(void);
static void sip_peer_hold(struct sip_pvt *p, int hold);
static void mwi_event_cb(const struct ast_event *, void *);
static void network_change_event_cb(const struct ast_event *, void *);
/*--- Applications, functions, CLI and manager command helpers */
Olle Johansson
committed
static const char *sip_nat_mode(const struct sip_pvt *p);
static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Russell Bryant
committed
static char *transfermode2str(enum transfermodes mode) attribute_const;
static int peer_status(struct sip_peer *peer, char *status, int statuslen);
static char *sip_show_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char * _sip_show_peers(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[]);
static char *sip_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static void print_group(int fd, ast_group_t group, int crlf);
Russell Bryant
committed
static const char *dtmfmode2str(int mode) attribute_const;
static int str2dtmfmode(const char *str) attribute_unused;
static const char *insecure2str(int mode) attribute_const;
static const char *allowoverlap2str(int mode) attribute_const;
static void cleanup_stale_contexts(char *new, char *old);
static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
static const char *domain_mode_to_text(const enum domain_mode mode);
static char *sip_show_domains(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]);
static char *sip_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]);
static char *sip_qualify_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Russell Bryant
committed
static const char *subscription_type2str(enum subscriptiontype subtype) attribute_pure;
static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
static char *complete_sip_peer(const char *word, int state, int flags2);
static char *complete_sip_registered_peer(const char *word, int state, int flags2);
Joshua Colp
committed
static char *complete_sip_show_history(const char *line, const char *word, int pos, int state);
static char *complete_sip_show_peer(const char *line, const char *word, int pos, int state);
static char *complete_sip_unregister(const char *line, const char *word, int pos, int state);
static char *complete_sipnotify(const char *line, const char *word, int pos, int state);
static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Olle Johansson
committed
static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_do_debug_ip(int fd, const char *arg);
static char *sip_do_debug_peer(int fd, const char *arg);
static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Joshua Colp
committed
static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static int sip_dtmfmode(struct ast_channel *chan, const char *data);
static int sip_addheader(struct ast_channel *chan, const char *data);
static int sip_do_reload(enum channelreloadreason reason);
static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr,
const char *name, int flag, int family);
static int ast_sockaddr_resolve_first(struct ast_sockaddr *addr,
const char *name, int flag);
Olle Johansson
committed
/*--- Debugging
Functions for enabling debug per IP or fully, or enabling history logging for
a SIP dialog
*/
static void sip_dump_history(struct sip_pvt *dialog); /* Dump history to debuglog at end of dialog, before destroying data */
static inline int sip_debug_test_addr(const struct ast_sockaddr *addr);
Olle Johansson
committed
static inline int sip_debug_test_pvt(struct sip_pvt *p);
Olle Johansson
committed
static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
static void sip_dump_history(struct sip_pvt *dialog);
Olle Johansson
committed
/*--- Device object handling */
static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime, int devstate_only);
Olle Johansson
committed
static int update_call_counter(struct sip_pvt *fup, int event);
static void sip_destroy_peer(struct sip_peer *peer);
static void sip_destroy_peer_fn(void *peer);
Olle Johansson
committed
static void set_peer_defaults(struct sip_peer *peer);
static struct sip_peer *temp_peer(const char *name);
static void register_peer_exten(struct sip_peer *peer, int onoff);
static int sip_poke_peer_s(const void *data);
static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
static void reg_source_db(struct sip_peer *peer);
static void destroy_association(struct sip_peer *peer);
static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno);
static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v);
static void set_socket_transport(struct sip_socket *socket, int transport);
Olle Johansson
committed
/* Realtime device support */
static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms);
static void update_peer(struct sip_peer *p, int expire);
static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
static const char *get_name_from_variable(const struct ast_variable *var);
static struct sip_peer *realtime_peer(const char *peername, struct ast_sockaddr *sin, int devstate_only, int which_objects);
static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Olle Johansson
committed
/*--- Internal UA client handling (outbound registrations) */
static void ast_sip_ouraddrfor(const struct ast_sockaddr *them, struct ast_sockaddr *us, struct sip_pvt *p);
Olle Johansson
committed
static void sip_registry_destroy(struct sip_registry *reg);
static int sip_register(const char *value, int lineno);
static const char *regstate2str(enum sipregistrystate regstate) attribute_const;
static int sip_reregister(const void *data);
static int __sip_do_register(struct sip_registry *r);
static int sip_reg_timeout(const void *data);
static void sip_send_all_registers(void);
static int sip_reinvite_retry(const void *data);
Olle Johansson
committed
/*--- Parsing SIP requests and responses */
static void append_date(struct sip_request *req); /* Append date to SIP packet */
static int determine_firstline_parts(struct sip_request *req);
Kevin P. Fleming
committed
static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize);
static int find_sip_method(const char *msg);
static unsigned int parse_allowed_methods(struct sip_request *req);
static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_request *req);
static int parse_request(struct sip_request *req);
static const char *referstatus2str(enum referstatus rstatus) attribute_pure;
Olle Johansson
committed
static int method_match(enum sipmethod id, const char *name);
static void parse_copy(struct sip_request *dst, const struct sip_request *src);
Olle Johansson
committed
static const char *find_alias(const char *name, const char *_default);
static const char *__get_header(const struct sip_request *req, const char *name, int *start);
static void lws2sws(struct ast_str *msgbuf);
Olle Johansson
committed
static void extract_uri(struct sip_pvt *p, struct sip_request *req);
Olle Johansson
committed
static char *remove_uri_parameters(char *uri);
static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
static int set_address_from_contact(struct sip_pvt *pvt);
static void check_via(struct sip_pvt *p, struct sip_request *req);
Mark Michelson
committed
static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
static int get_msg_text(char *buf, int len, struct sip_request *req);
Olle Johansson
committed
static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
Mark Michelson
committed
static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
static int get_domain(const char *str, char *domain, int len);
Matthew Nicholson
committed
static void get_realm(struct sip_pvt *p, const struct sip_request *req);
Olle Johansson
committed
/*-- TCP connection handling ---*/
Russell Bryant
committed
static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session);
static void *sip_tcp_worker_fn(void *);
Olle Johansson
committed
/*--- Constructing requests and responses */
static void initialize_initreq(struct sip_pvt *p, struct sip_request *req);
static int init_req(struct sip_request *req, int sipmethod, const char *recip);
static void deinit_req(struct sip_request *req);
Olle Johansson
committed
static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch);
static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, const char * const explicit_uri);
static int init_resp(struct sip_request *resp, const char *msg);
static inline int resp_needs_contact(const char *msg, enum sipmethod method);
static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req);
static const struct ast_sockaddr *sip_real_dst(const struct sip_pvt *p);
Olle Johansson
committed
static void build_via(struct sip_pvt *p);
static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
static int create_addr(struct sip_pvt *dialog, const char *opeer, struct ast_sockaddr *addr, int newdialog, struct ast_sockaddr *remote_address);
Olle Johansson
committed
static char *generate_random_string(char *buf, size_t size);
static void build_callid_pvt(struct sip_pvt *pvt);
static void change_callid_pvt(struct sip_pvt *pvt, const char *callid);
static void build_callid_registry(struct sip_registry *reg, const struct ast_sockaddr *ourip, const char *fromdomain);
Olle Johansson
committed
static void make_our_tag(char *tagbuf, size_t len);
static int add_header(struct sip_request *req, const char *var, const char *value);
Olle Johansson
committed
static int add_header_max_forwards(struct sip_pvt *dialog, struct sip_request *req);
static int add_content(struct sip_request *req, const char *line);
static int finalize_content(struct sip_request *req);
Olle Johansson
committed
static int add_text(struct sip_request *req, const char *text);
static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
Mark Michelson
committed
static int add_rpid(struct sip_request *req, struct sip_pvt *p);
Olle Johansson
committed
static int add_vidupdate(struct sip_request *req);
static void add_route(struct sip_request *req, struct sip_route *route);
static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
Olle Johansson
committed
static void set_destination(struct sip_pvt *p, char *uri);
static void append_date(struct sip_request *req);
static void build_contact(struct sip_pvt *p);
/*------Request handling functions */
static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int *recount, int *nounlock);
static int handle_request_update(struct sip_pvt *p, struct sip_request *req);
static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *recount, const char *e, int *nounlock);
static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, int *nounlock);
static int handle_request_bye(struct sip_pvt *p, struct sip_request *req);
static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *sin, const char *e);
static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
static int handle_request_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e);
static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
static int handle_request_options(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e);
static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *nounlock);
static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e);
static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno, int *nounlock);
/*------Response handling functions */
static void handle_response_publish(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static int handle_response_register(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
/*------ SRTP Support -------- */
static int setup_srtp(struct sip_srtp **srtp);
static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct sip_srtp **srtp, const char *a);
/*------ T38 Support --------- */
static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
Joshua Colp
committed
static void change_t38_state(struct sip_pvt *p, int state);
Russell Bryant
committed
/*------ Session-Timers functions --------- */
static void proc_422_rsp(struct sip_pvt *p, struct sip_request *rsp);
static int proc_session_timer(const void *vp);
static void stop_session_timer(struct sip_pvt *p);
static void start_session_timer(struct sip_pvt *p);
static void restart_session_timer(struct sip_pvt *p);
static const char *strefresher2str(enum st_refresher r);
static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher *const p_ref);
static int parse_minse(const char *p_hdrval, int *const p_interval);
static int st_get_se(struct sip_pvt *, int max);
static enum st_refresher st_get_refresher(struct sip_pvt *);
static enum st_mode st_get_mode(struct sip_pvt *, int no_cached);
Russell Bryant
committed
static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p);
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, const struct ast_format_cap *cap, int nat_active);
/*!--- SIP MWI Subscription support */
static int sip_subscribe_mwi(const char *value, int lineno);
static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi);
static void sip_send_all_mwi_subscriptions(void);
static int sip_subscribe_mwi_do(const void *data);
static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi);
Russell Bryant
committed
/*! \brief Definition of this channel for PBX channel registration */
struct ast_channel_tech sip_tech = {
.description = "Session Initiation Protocol (SIP)",
Russell Bryant
committed
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
.requester = sip_request_call, /* called with chan unlocked */
.devicestate = sip_devicestate, /* called with chan unlocked (not chan-specific) */
.call = sip_call, /* called with chan locked */
.hangup = sip_hangup, /* called with chan locked */
.answer = sip_answer, /* called with chan locked */
.read = sip_read, /* called with chan locked */
.write = sip_write, /* called with chan locked */
.write_video = sip_write, /* called with chan locked */
.write_text = sip_write,
.indicate = sip_indicate, /* called with chan locked */
.transfer = sip_transfer, /* called with chan locked */
.fixup = sip_fixup, /* called with chan locked */
.send_digit_begin = sip_senddigit_begin, /* called with chan unlocked */
.send_digit_end = sip_senddigit_end,
.bridge = ast_rtp_instance_bridge, /* XXX chan unlocked ? */
.early_bridge = ast_rtp_instance_early_bridge,
.send_text = sip_sendtext, /* called with chan locked */
Tilghman Lesher
committed
.func_channel_read = sip_acf_channel_read,
.setoption = sip_setoption,
Joshua Colp
committed
.queryoption = sip_queryoption,
.get_pvt_uniqueid = sip_get_callid,
};
/*! \brief This version of the sip channel tech has no send_digit_begin
* callback so that the core knows that the channel does not want
* DTMF BEGIN frames.
* The struct is initialized just before registering the channel driver,
* and is for use with channels using SIP INFO DTMF.
*/
Tilghman Lesher
committed
struct ast_channel_tech sip_tech_info;
/*------- CC Support -------- */
static int sip_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan);
static int sip_cc_agent_start_offer_timer(struct ast_cc_agent *agent);
static int sip_cc_agent_stop_offer_timer(struct ast_cc_agent *agent);
static void sip_cc_agent_respond(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason);
static int sip_cc_agent_status_request(struct ast_cc_agent *agent);
static int sip_cc_agent_start_monitoring(struct ast_cc_agent *agent);
static int sip_cc_agent_recall(struct ast_cc_agent *agent);
static void sip_cc_agent_destructor(struct ast_cc_agent *agent);
static struct ast_cc_agent_callbacks sip_cc_agent_callbacks = {
.type = "SIP",
.init = sip_cc_agent_init,
.start_offer_timer = sip_cc_agent_start_offer_timer,
.stop_offer_timer = sip_cc_agent_stop_offer_timer,
.respond = sip_cc_agent_respond,
.status_request = sip_cc_agent_status_request,
.start_monitoring = sip_cc_agent_start_monitoring,
.callee_available = sip_cc_agent_recall,
.destructor = sip_cc_agent_destructor,
static int find_by_notify_uri_helper(void *obj, void *arg, int flags)
{
struct ast_cc_agent *agent = obj;
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
const char *uri = arg;
return !sip_uri_cmp(agent_pvt->notify_uri, uri) ? CMP_MATCH | CMP_STOP : 0;
static struct ast_cc_agent *find_sip_cc_agent_by_notify_uri(const char * const uri)
struct ast_cc_agent *agent = ast_cc_agent_callback(0, find_by_notify_uri_helper, (char *)uri, "SIP");
return agent;
static int find_by_subscribe_uri_helper(void *obj, void *arg, int flags)
struct ast_cc_agent *agent = obj;
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
const char *uri = arg;
return !sip_uri_cmp(agent_pvt->subscribe_uri, uri) ? CMP_MATCH | CMP_STOP : 0;
static struct ast_cc_agent *find_sip_cc_agent_by_subscribe_uri(const char * const uri)
struct ast_cc_agent *agent = ast_cc_agent_callback(0, find_by_subscribe_uri_helper, (char *)uri, "SIP");
return agent;
static int find_by_callid_helper(void *obj, void *arg, int flags)
struct ast_cc_agent *agent = obj;
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
struct sip_pvt *call_pvt = arg;
return !strcmp(agent_pvt->original_callid, call_pvt->callid) ? CMP_MATCH | CMP_STOP : 0;
static struct ast_cc_agent *find_sip_cc_agent_by_original_callid(struct sip_pvt *pvt)
struct ast_cc_agent *agent = ast_cc_agent_callback(0, find_by_callid_helper, pvt, "SIP");
return agent;
}
static int sip_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
{
struct sip_cc_agent_pvt *agent_pvt = ast_calloc(1, sizeof(*agent_pvt));
struct sip_pvt *call_pvt = chan->tech_pvt;
if (!agent_pvt) {
return -1;
ast_assert(!strcmp(chan->tech->type, "SIP"));
ast_copy_string(agent_pvt->original_callid, call_pvt->callid, sizeof(agent_pvt->original_callid));
ast_copy_string(agent_pvt->original_exten, call_pvt->exten, sizeof(agent_pvt->original_exten));
agent_pvt->offer_timer_id = -1;
agent->private_data = agent_pvt;
sip_pvt_lock(call_pvt);
ast_set_flag(&call_pvt->flags[0], SIP_OFFER_CC);
sip_pvt_unlock(call_pvt);
return 0;
static int sip_offer_timer_expire(const void *data)
struct ast_cc_agent *agent = (struct ast_cc_agent *) data;
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
agent_pvt->offer_timer_id = -1;
return ast_cc_failed(agent->core_id, "SIP agent %s's offer timer expired", agent->device_name);
static int sip_cc_agent_start_offer_timer(struct ast_cc_agent *agent)
{
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
int when;
when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
agent_pvt->offer_timer_id = ast_sched_add(sched, when, sip_offer_timer_expire, agent);
return 0;
}
static int sip_cc_agent_stop_offer_timer(struct ast_cc_agent *agent)
Olle Johansson
committed
{
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
Olle Johansson
committed
AST_SCHED_DEL(sched, agent_pvt->offer_timer_id);
return 0;
Olle Johansson
committed
}
static void sip_cc_agent_respond(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason)
{
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
sip_pvt_lock(agent_pvt->subscribe_pvt);
ast_set_flag(&agent_pvt->subscribe_pvt->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED);
if (reason == AST_CC_AGENT_RESPONSE_SUCCESS || !ast_strlen_zero(agent_pvt->notify_uri)) {
/* The second half of this if statement may be a bit hard to grasp,
* so here's an explanation. When a subscription comes into
* chan_sip, as long as it is not malformed, it will be passed
* to the CC core. If the core senses an out-of-order state transition,
* then the core will call this callback with the "reason" set to a
* failure condition.
* However, an out-of-order state transition will occur during a resubscription
* for CC. In such a case, we can see that we have already generated a notify_uri
* and so we can detect that this isn't a *real* failure. Rather, it is just
* something the core doesn't recognize as a legitimate SIP state transition.
* Thus we respond with happiness and flowers.
*/
transmit_response(agent_pvt->subscribe_pvt, "200 OK", &agent_pvt->subscribe_pvt->initreq);
transmit_cc_notify(agent, agent_pvt->subscribe_pvt, CC_QUEUED);
} else {
transmit_response(agent_pvt->subscribe_pvt, "500 Internal Error", &agent_pvt->subscribe_pvt->initreq);
}
sip_pvt_unlock(agent_pvt->subscribe_pvt);
agent_pvt->is_available = TRUE;
}
static int sip_cc_agent_status_request(struct ast_cc_agent *agent)
{
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
enum ast_device_state state = agent_pvt->is_available ? AST_DEVICE_NOT_INUSE : AST_DEVICE_INUSE;
return ast_cc_agent_status_response(agent->core_id, state);
}
static int sip_cc_agent_start_monitoring(struct ast_cc_agent *agent)
{
/* To start monitoring just means to wait for an incoming PUBLISH
* to tell us that the caller has become available again. No special
* action is needed
*/
return 0;
}
static int sip_cc_agent_recall(struct ast_cc_agent *agent)
{
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
/* If we have received a PUBLISH beforehand stating that the caller in question
* is not available, we can save ourself a bit of effort here and just report
* the caller as busy
*/
if (!agent_pvt->is_available) {
return ast_cc_agent_caller_busy(agent->core_id, "Caller %s is busy, reporting to the core",
agent->device_name);
}
/* Otherwise, we transmit a NOTIFY to the caller and await either
* a PUBLISH or an INVITE
*/
sip_pvt_lock(agent_pvt->subscribe_pvt);
transmit_cc_notify(agent, agent_pvt->subscribe_pvt, CC_READY);
sip_pvt_unlock(agent_pvt->subscribe_pvt);
return 0;
}
static void sip_cc_agent_destructor(struct ast_cc_agent *agent)
{
struct sip_cc_agent_pvt *agent_pvt = agent->private_data;
if (!agent_pvt) {
/* The agent constructor probably failed. */
return;
}
sip_cc_agent_stop_offer_timer(agent);
if (agent_pvt->subscribe_pvt) {
sip_pvt_lock(agent_pvt->subscribe_pvt);
if (!ast_test_flag(&agent_pvt->subscribe_pvt->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED)) {
/* If we haven't sent a 200 OK for the SUBSCRIBE dialog yet, then we need to send a response letting
* the subscriber know something went wrong
*/
transmit_response(agent_pvt->subscribe_pvt, "500 Internal Server Error", &agent_pvt->subscribe_pvt->initreq);
}
sip_pvt_unlock(agent_pvt->subscribe_pvt);
agent_pvt->subscribe_pvt = dialog_unref(agent_pvt->subscribe_pvt, "SIP CC agent destructor: Remove ref to subscription");
}
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
struct ao2_container *sip_monitor_instances;
static int sip_monitor_instance_hash_fn(const void *obj, const int flags)
{
const struct sip_monitor_instance *monitor_instance = obj;
return monitor_instance->core_id;
}
static int sip_monitor_instance_cmp_fn(void *obj, void *arg, int flags)
{
struct sip_monitor_instance *monitor_instance1 = obj;
struct sip_monitor_instance *monitor_instance2 = arg;
return monitor_instance1->core_id == monitor_instance2->core_id ? CMP_MATCH | CMP_STOP : 0;
}
static void sip_monitor_instance_destructor(void *data)
{
struct sip_monitor_instance *monitor_instance = data;
if (monitor_instance->subscription_pvt) {
sip_pvt_lock(monitor_instance->subscription_pvt);
monitor_instance->subscription_pvt->expiry = 0;
transmit_invite(monitor_instance->subscription_pvt, SIP_SUBSCRIBE, FALSE, 0, monitor_instance->subscribe_uri);
sip_pvt_unlock(monitor_instance->subscription_pvt);
dialog_unref(monitor_instance->subscription_pvt, "Unref monitor instance ref of subscription pvt");
}
if (monitor_instance->suspension_entry) {
monitor_instance->suspension_entry->body[0] = '\0';
transmit_publish(monitor_instance->suspension_entry, SIP_PUBLISH_REMOVE ,monitor_instance->notify_uri);
ao2_t_ref(monitor_instance->suspension_entry, -1, "Decrementing suspension entry refcount in sip_monitor_instance_destructor");
}
ast_string_field_free_memory(monitor_instance);
}
static struct sip_monitor_instance *sip_monitor_instance_init(int core_id, const char * const subscribe_uri, const char * const peername, const char * const device_name)
{
struct sip_monitor_instance *monitor_instance = ao2_alloc(sizeof(*monitor_instance), sip_monitor_instance_destructor);
return NULL;
}
if (ast_string_field_init(monitor_instance, 256)) {
ao2_ref(monitor_instance, -1);
return NULL;
}
ast_string_field_set(monitor_instance, subscribe_uri, subscribe_uri);
ast_string_field_set(monitor_instance, peername, peername);
ast_string_field_set(monitor_instance, device_name, device_name);
monitor_instance->core_id = core_id;
ao2_link(sip_monitor_instances, monitor_instance);
return monitor_instance;
}
static int find_sip_monitor_instance_by_subscription_pvt(void *obj, void *arg, int flags)
{
struct sip_monitor_instance *monitor_instance = obj;
return monitor_instance->subscription_pvt == arg ? CMP_MATCH | CMP_STOP : 0;
}
static int find_sip_monitor_instance_by_suspension_entry(void *obj, void *arg, int flags)
{
struct sip_monitor_instance *monitor_instance = obj;
return monitor_instance->suspension_entry == arg ? CMP_MATCH | CMP_STOP : 0;
}
static int sip_cc_monitor_request_cc(struct ast_cc_monitor *monitor, int *available_timer_id);
static int sip_cc_monitor_suspend(struct ast_cc_monitor *monitor);
static int sip_cc_monitor_unsuspend(struct ast_cc_monitor *monitor);
static int sip_cc_monitor_cancel_available_timer(struct ast_cc_monitor *monitor, int *sched_id);
static void sip_cc_monitor_destructor(void *private_data);
static struct ast_cc_monitor_callbacks sip_cc_monitor_callbacks = {
.type = "SIP",
.request_cc = sip_cc_monitor_request_cc,
.suspend = sip_cc_monitor_suspend,
.unsuspend = sip_cc_monitor_unsuspend,
.cancel_available_timer = sip_cc_monitor_cancel_available_timer,
.destructor = sip_cc_monitor_destructor,
};
static int sip_cc_monitor_request_cc(struct ast_cc_monitor *monitor, int *available_timer_id)
{
struct sip_monitor_instance *monitor_instance = monitor->private_data;
enum ast_cc_service_type service = monitor->service_offered;
int when;
if (!monitor_instance) {
return -1;
}
if (!(monitor_instance->subscription_pvt = sip_alloc(NULL, NULL, 0, SIP_SUBSCRIBE, NULL))) {
return -1;
}
when = service == AST_CC_CCBS ? ast_get_ccbs_available_timer(monitor->interface->config_params) :
ast_get_ccnr_available_timer(monitor->interface->config_params);
sip_pvt_lock(monitor_instance->subscription_pvt);
ast_set_flag(&monitor_instance->subscription_pvt->flags[0], SIP_OUTGOING);
create_addr(monitor_instance->subscription_pvt, monitor_instance->peername, 0, 1, NULL);
ast_sip_ouraddrfor(&monitor_instance->subscription_pvt->sa, &monitor_instance->subscription_pvt->ourip, monitor_instance->subscription_pvt);
monitor_instance->subscription_pvt->subscribed = CALL_COMPLETION;
monitor_instance->subscription_pvt->expiry = when;
transmit_invite(monitor_instance->subscription_pvt, SIP_SUBSCRIBE, FALSE, 2, monitor_instance->subscribe_uri);
sip_pvt_unlock(monitor_instance->subscription_pvt);
ao2_t_ref(monitor, +1, "Adding a ref to the monitor for the scheduler");
*available_timer_id = ast_sched_add(sched, when * 1000, ast_cc_available_timer_expire, monitor);
return 0;
}
static int construct_pidf_body(enum sip_cc_publish_state state, char *pidf_body, size_t size, const char *presentity)
struct ast_str *body = ast_str_alloca(size);
char tuple_id[32];
generate_random_string(tuple_id, sizeof(tuple_id));
/* We'll make this a bare-bones pidf body. In state_notify_build_xml, the PIDF
* body gets a lot more extra junk that isn't necessary, so we'll leave it out here.
*/
ast_str_append(&body, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
/* XXX The entity attribute is currently set to the peer name associated with the
* dialog. This is because we currently only call this function for call-completion
* PUBLISH bodies. In such cases, the entity is completely disregarded. For other
* event packages, it may be crucial to have a proper URI as the presentity so this
* should be revisited as support is expanded.
*/
ast_str_append(&body, 0, "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" entity=\"%s\">\n", presentity);
ast_str_append(&body, 0, "<tuple id=\"%s\">\n", tuple_id);
ast_str_append(&body, 0, "<status><basic>%s</basic></status>\n", state == CC_OPEN ? "open" : "closed");
ast_str_append(&body, 0, "</tuple>\n");
ast_str_append(&body, 0, "</presence>\n");
ast_copy_string(pidf_body, ast_str_buffer(body), size);
return 0;
static int sip_cc_monitor_suspend(struct ast_cc_monitor *monitor)
struct sip_monitor_instance *monitor_instance = monitor->private_data;
enum sip_publish_type publish_type;
struct cc_epa_entry *cc_entry;
if (!monitor_instance) {
return -1;
}
if (!monitor_instance->suspension_entry) {
/* We haven't yet allocated the suspension entry, so let's give it a shot */
if (!(monitor_instance->suspension_entry = create_epa_entry("call-completion", monitor_instance->peername))) {
ast_log(LOG_WARNING, "Unable to allocate sip EPA entry for call-completion\n");
ao2_ref(monitor_instance, -1);
return -1;
}
if (!(cc_entry = ast_calloc(1, sizeof(*cc_entry)))) {
ast_log(LOG_WARNING, "Unable to allocate space for instance data of EPA entry for call-completion\n");
ao2_ref(monitor_instance, -1);
return -1;