Newer
Older
/*! \brief A bogus peer, to be used when authentication should fail */
static struct sip_peer *bogus_peer;
/*! \brief We can recognise the bogus peer by this invalid MD5 hash */
#define BOGUS_PEER_MD5SECRET "intentionally_invalid_md5_string"
/*! \brief The register list: Other SIP proxies we register with and receive calls from */
static struct ao2_container *registry_list;
/*! \brief The MWI subscription list */
static struct ao2_container *subscription_mwi_list;
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 A per-thread buffer for transport to string conversion */
AST_THREADSTORAGE(sip_transport_str_buf);
/*! \brief Size of the SIP transport buffer */
#define SIP_TRANSPORT_STR_BUFSIZE 128
/*! \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);
static struct ast_manager_event_blob *session_timeout_to_ami(struct stasis_message *msg);
STASIS_MESSAGE_TYPE_DEFN_LOCAL(session_timeout_type,
.to_ami = session_timeout_to_ami,
);
/* --- 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 struct ast_sockaddr rtpbindaddr; /*!< RTP: The address we bind to */
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)
struct ao2_container *sip_monitor_instances;
Matthew Jordan
committed
struct show_peers_context;
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_assigned_ids *assignedids, const struct ast_channel *requestor, const char *dest, int *cause);
static int sip_devicestate(const char *data);
Olle Johansson
committed
static int sip_sendtext(struct ast_channel *ast, const char *text);
static int sip_call(struct ast_channel *ast, const 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 ast_transport type, int port);
static int sip_prepare_socket(struct sip_pvt *p);
static int get_address_family_filter(unsigned int transport);
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, uint32_t 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, struct sip_request *req, enum xmittype reliable);
static int transmit_request(struct sip_pvt *p, int sipmethod, uint32_t seqno, enum xmittype reliable, int newbranch);
static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, uint32_t 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(struct sip_pvt *p, int init, int auth);
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);
static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, uint32_t seqno);
static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, uint32_t 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);
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 build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp);
static int build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, const char *pathbuf);
static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
struct sip_request *req, const char *uri);
static int get_sip_pvt_from_replaces(const char *callid, const char *totag, const char *fromtag,
struct sip_pvt **out_pvt, struct ast_channel **out_chan);
static void check_pendings(struct sip_pvt *p);
static void sip_set_owner(struct sip_pvt *p, struct ast_channel *chan);
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_ice(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance);
static int process_sdp_a_dtls(const char *a, struct sip_pvt *p, struct ast_rtp_instance *instance);
Matthew Nicholson
committed
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_ice_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
Joshua Colp
committed
static void start_ice(struct ast_rtp_instance *instance, int offer);
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,
Matthew Jordan
committed
int debug, int *min_packet_size, int *max_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,
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(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_alloc(struct sip_pvt *p);
static int sip_notify_alloc(struct sip_pvt *p);
static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
Michael L. Young
committed
static void set_peer_nat(const struct sip_pvt *p, struct sip_peer *peer);
static void check_for_nat(const struct ast_sockaddr *them, struct sip_pvt *p);
Olle Johansson
committed
/*--- Device monitoring and Device/extension state/event handling */
static int extensionstate_update(const char *context, const char *exten, struct state_notify_data *data, struct sip_pvt *p, int force);
static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, 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(void *, struct stasis_subscription *, struct stasis_message *);
static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
static void sip_keepalive_all_peers(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[]);
Matthew Jordan
committed
static struct sip_peer *_sip_show_peers_one(int fd, struct mansession *s, struct show_peers_context *cont, struct sip_peer *peer);
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);
static void print_named_groups(int fd, struct ast_namedgroups *groups, 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 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_sip_notify(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);
static int ast_sockaddr_resolve_first_transport(struct ast_sockaddr *addr,
const char *name, int flag, unsigned int transport);
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);
static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags);
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, const char *path);
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, char *callbackexten, 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);
static void sip_registry_destroy(void *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 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);
static void parse_oli(struct sip_request *req, struct ast_channel *chan);
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, const 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, char **reason_str);
static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id);
static int transmit_state_notify(struct sip_pvt *p, struct state_notify_data *data, 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 ---*/
static void *_sip_tcp_helper_thread(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);
static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, uint32_t 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);
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);
static void build_localtag_registry(struct sip_registry *reg);
static void make_our_tag(struct sip_pvt *pvt);
Olle Johansson
committed
static int add_header(struct sip_request *req, const char *var, const char *value);
static int add_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);
static void destroy_msg_headers(struct sip_pvt *pvt);
static int add_text(struct sip_request *req, struct sip_pvt *p);
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, int skip);
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);
static void set_destination(struct sip_pvt *p, const char *uri);
static void add_date(struct sip_request *req);
static void add_expires(struct sip_request *req, int expires);
Olle Johansson
committed
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, struct ast_sockaddr *addr, uint32_t seqno, int *recount, const char *e, int *nounlock);
static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint32_t 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, uint32_t 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 *nounlock, struct sip_pvt *replaces_pvt, struct ast_channel *replaces_chan);
static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, uint32_t seqno, const char *e);
static int local_attended_transfer(struct sip_pvt *transferer, struct ast_channel *transferer_chan, uint32_t seqno, int *nounlock);
/*------Response handling functions */
static void handle_response_publish(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
static int handle_response_register(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, uint32_t seqno);
static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struct ast_sdp_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);
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 *strefresherparam2str(enum st_refresher r);
static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher_param *const p_ref);
Russell Bryant
committed
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(void *data);
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,
.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,
/* -------- End of declarations of structures, constants and forward declarations of functions
Matthew Jordan
committed
Below starts actual code
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
------------------------
*/
static int sip_epa_register(const struct epa_static_data *static_data)
{
struct epa_backend *backend = ast_calloc(1, sizeof(*backend));
if (!backend) {
return -1;
}
backend->static_data = static_data;
AST_LIST_LOCK(&epa_static_data_list);
AST_LIST_INSERT_TAIL(&epa_static_data_list, backend, next);
AST_LIST_UNLOCK(&epa_static_data_list);
return 0;
}
static void sip_epa_unregister_all(void)
{
struct epa_backend *backend;
AST_LIST_LOCK(&epa_static_data_list);
while ((backend = AST_LIST_REMOVE_HEAD(&epa_static_data_list, next))) {
ast_free(backend);
}
AST_LIST_UNLOCK(&epa_static_data_list);
}
static void cc_handle_publish_error(struct sip_pvt *pvt, const int resp, struct sip_request *req, struct sip_epa_entry *epa_entry);
static void cc_epa_destructor(void *data)
{
struct sip_epa_entry *epa_entry = data;
struct cc_epa_entry *cc_entry = epa_entry->instance_data;
ast_free(cc_entry);
}
static const struct epa_static_data cc_epa_static_data = {
.event = CALL_COMPLETION,
.name = "call-completion",
.handle_error = cc_handle_publish_error,
.destructor = cc_epa_destructor,
};
static const struct epa_static_data *find_static_data(const char * const event_package)
{
const struct epa_backend *backend = NULL;
AST_LIST_LOCK(&epa_static_data_list);
AST_LIST_TRAVERSE(&epa_static_data_list, backend, next) {
if (!strcmp(backend->static_data->name, event_package)) {
break;
}
}
AST_LIST_UNLOCK(&epa_static_data_list);
return backend ? backend->static_data : NULL;
}
static struct sip_epa_entry *create_epa_entry (const char * const event_package, const char * const destination)
{
struct sip_epa_entry *epa_entry;
const struct epa_static_data *static_data;
if (!(static_data = find_static_data(event_package))) {
return NULL;
}
if (!(epa_entry = ao2_t_alloc(sizeof(*epa_entry), static_data->destructor, "Allocate new EPA entry"))) {
return NULL;
}
epa_entry->static_data = static_data;
ast_copy_string(epa_entry->destination, destination, sizeof(epa_entry->destination));
return epa_entry;
}
static enum ast_cc_service_type service_string_to_service_type(const char * const service_string)
{
enum ast_cc_service_type service;
for (service = AST_CC_CCBS; service <= AST_CC_CCNL; ++service) {
if (!strcasecmp(service_string, sip_cc_service_map[service].service_string)) {
return service;
}
}
return AST_CC_NONE;
}
/* Even state compositors code */
static void esc_entry_destructor(void *obj)
{
struct sip_esc_entry *esc_entry = obj;
if (esc_entry->sched_id > -1) {
AST_SCHED_DEL(sched, esc_entry->sched_id);
}
}
static int esc_hash_fn(const void *obj, const int flags)
{
const struct sip_esc_entry *entry = obj;
return ast_str_hash(entry->entity_tag);
}
static int esc_cmp_fn(void *obj, void *arg, int flags)
{
struct sip_esc_entry *entry1 = obj;
struct sip_esc_entry *entry2 = arg;
return (!strcmp(entry1->entity_tag, entry2->entity_tag)) ? (CMP_MATCH | CMP_STOP) : 0;
}
static struct event_state_compositor *get_esc(const char * const event_package) {
int i;
for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
if (!strcasecmp(event_package, event_state_compositors[i].name)) {
return &event_state_compositors[i];
}
}
return NULL;
}
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_cleanup(event_state_compositors[i].compositor);
}
}
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 = ast_channel_tech_pvt(chan);
if (!agent_pvt) {
return -1;
ast_assert(!strcmp(ast_channel_tech(chan)->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");
}
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
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);