Newer
Older
{ REFER_200OK, "Done" },
{ REFER_FAILED, "Failed" },
{ REFER_NOAUTH, "Failed - auth failure" },
{ -1, NULL} /* terminator */
};
/*! \brief Structure to handle SIP transfers. Dynamically allocated when needed
\note OEJ: Should be moved to string fields */
struct sip_refer {
char refer_to[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO extension */
char refer_to_domain[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO domain */
char refer_to_urioption[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO uri options */
char refer_to_context[AST_MAX_EXTENSION]; /*!< Place to store REFER-TO context */
char referred_by[AST_MAX_EXTENSION]; /*!< Place to store REFERRED-BY extension */
char referred_by_name[AST_MAX_EXTENSION]; /*!< Place to store REFERRED-BY extension */
char refer_contact[AST_MAX_EXTENSION]; /*!< Place to store Contact info from a REFER extension */
char replaces_callid[BUFSIZ]; /*!< Replace info: callid */
char replaces_callid_totag[BUFSIZ/2]; /*!< Replace info: to-tag */
char replaces_callid_fromtag[BUFSIZ/2]; /*!< Replace info: from-tag */
struct sip_pvt *refer_call; /*!< Call we are referring. This is just a reference to a
* dialog owned by someone else, so we should not destroy
* it when the sip_refer object goes.
*/
int attendedtransfer; /*!< Attended or blind transfer? */
int localtransfer; /*!< Transfer to local domain? */
enum referstatus status; /*!< REFER status */
};
/*! \brief sip_pvt: structures used for each SIP dialog, ie. a call, a registration, a subscribe.
* Created and initialized by sip_alloc(), the descriptor goes into the list of
* descriptors (dialoglist).
*/
struct sip_pvt {
struct sip_pvt *next; /*!< Next dialog in chain */
ast_mutex_t pvt_lock; /*!< Dialog private lock */
Olle Johansson
committed
enum invitestates invitestate; /*!< Track state of SIP_INVITEs */
Olle Johansson
committed
int method; /*!< SIP method that opened this dialog */
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(callid); /*!< Global CallID */
AST_STRING_FIELD(randdata); /*!< Random data */
AST_STRING_FIELD(accountcode); /*!< Account code */
AST_STRING_FIELD(realm); /*!< Authorization realm */
AST_STRING_FIELD(nonce); /*!< Authorization nonce */
AST_STRING_FIELD(opaque); /*!< Opaque nonsense */
AST_STRING_FIELD(qop); /*!< Quality of Protection, since SIP wasn't complicated enough yet. */
AST_STRING_FIELD(domain); /*!< Authorization domain */
AST_STRING_FIELD(from); /*!< The From: header */
AST_STRING_FIELD(useragent); /*!< User agent in SIP request */
AST_STRING_FIELD(exten); /*!< Extension where to start */
AST_STRING_FIELD(context); /*!< Context for this call */
AST_STRING_FIELD(subscribecontext); /*!< Subscribecontext */
Olle Johansson
committed
AST_STRING_FIELD(subscribeuri); /*!< Subscribecontext */
AST_STRING_FIELD(fromdomain); /*!< Domain to show in the from field */
AST_STRING_FIELD(fromuser); /*!< User to show in the user field */
AST_STRING_FIELD(fromname); /*!< Name to show in the user field */
AST_STRING_FIELD(tohost); /*!< Host we should put in the "to" field */
AST_STRING_FIELD(todnid); /*!< DNID of this call (overrides host) */
AST_STRING_FIELD(language); /*!< Default language for this call */
Kevin P. Fleming
committed
AST_STRING_FIELD(mohinterpret); /*!< MOH class to use when put on hold */
AST_STRING_FIELD(mohsuggest); /*!< MOH class to suggest when putting a peer on hold */
AST_STRING_FIELD(rdnis); /*!< Referring DNIS */
Olle Johansson
committed
AST_STRING_FIELD(redircause); /*!< Referring cause */
AST_STRING_FIELD(theirtag); /*!< Their tag */
AST_STRING_FIELD(username); /*!< [user] name */
AST_STRING_FIELD(peername); /*!< [peer] name, not set if [user] */
AST_STRING_FIELD(authname); /*!< Who we use for authentication */
AST_STRING_FIELD(uri); /*!< Original requested URI */
AST_STRING_FIELD(okcontacturi); /*!< URI from the 200 OK on INVITE */
AST_STRING_FIELD(peersecret); /*!< Password */
AST_STRING_FIELD(peermd5secret);
AST_STRING_FIELD(cid_num); /*!< Caller*ID number */
AST_STRING_FIELD(cid_name); /*!< Caller*ID name */
AST_STRING_FIELD(via); /*!< Via: header */
AST_STRING_FIELD(fullcontact); /*!< The Contact: that the UA registers with us */
/* we only store the part in <brackets> in this field. */
AST_STRING_FIELD(our_contact); /*!< Our contact header */
AST_STRING_FIELD(rpid); /*!< Our RPID header */
AST_STRING_FIELD(rpid_from); /*!< Our RPID From header */
Kevin P. Fleming
committed
AST_STRING_FIELD(url); /*!< URL to be sent with next message to peer */
unsigned int ocseq; /*!< Current outgoing seqno */
unsigned int icseq; /*!< Current incoming seqno */
ast_group_t callgroup; /*!< Call group */
ast_group_t pickupgroup; /*!< Pickup group */
int lastinvite; /*!< Last Cseq of invite */
int lastnoninvite; /*!< Last Cseq of non-invite */
struct ast_flags flags[2]; /*!< SIP_ flags */
/* boolean or small integers that don't belong in flags */
char do_history; /*!< Set if we want to record history */
char alreadygone; /*!< already destroyed by our peer */
char needdestroy; /*!< need to be destroyed by the monitor thread */
char outgoing_call; /*!< this is an outgoing call */
char answered_elsewhere; /*!< This call is cancelled due to answer on another channel */
char novideo; /*!< Didn't get video in invite, don't offer */
char notext; /*!< Text not supported (?) */
int timer_t1; /*!< SIP timer T1, ms rtt */
Olle Johansson
committed
int timer_b; /*!< SIP timer B, ms */
unsigned int sipoptions; /*!< Supported SIP options on the other end */
struct ast_codec_pref prefs; /*!< codec prefs */
int capability; /*!< Special capability (codec) */
int jointcapability; /*!< Supported capability at both ends (codecs) */
int peercapability; /*!< Supported peer capability */
int prefcodec; /*!< Preferred codec (outbound only) */
int noncodeccapability; /*!< DTMF RFC2833 telephony-event */
int jointnoncodeccapability; /*!< Joint Non codec capability */
int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */
struct sip_proxy *outboundproxy; /*!< Outbound proxy for this dialog */
struct t38properties t38; /*!< T38 settings */
struct sockaddr_in udptlredirip; /*!< Where our T.38 UDPTL should be going if not to us */
struct ast_udptl *udptl; /*!< T.38 UDPTL session */
int callingpres; /*!< Calling presentation */
int authtries; /*!< Times we've tried to authenticate */
int expiry; /*!< How long we take to expire */
long branch; /*!< The branch identifier of this session */
char tag[11]; /*!< Our tag for this session */
int sessionid; /*!< SDP Session ID */
int sessionversion; /*!< SDP Session Version */
struct sockaddr_in sa; /*!< Our peer */
struct sockaddr_in redirip; /*!< Where our RTP should be going if not to us */
struct sockaddr_in vredirip; /*!< Where our Video RTP should be going if not to us */
struct sockaddr_in tredirip; /*!< Where our Text RTP should be going if not to us */
time_t lastrtprx; /*!< Last RTP received */
time_t lastrtptx; /*!< Last RTP sent */
int rtptimeout; /*!< RTP timeout time */
struct sockaddr_in recv; /*!< Received as */
struct sockaddr_in ourip; /*!< Our IP (as seen from the outside) */
struct ast_channel *owner; /*!< Who owns us (if we have an owner) */
struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */
int route_persistant; /*!< Is this the "real" route? */
struct sip_auth *peerauth; /*!< Realm authentication */
int noncecount; /*!< Nonce-count */
char lastmsg[256]; /*!< Last Message sent/received */
int amaflags; /*!< AMA Flags */
int pendinginvite; /*!< Any pending invite ? (seqno of this) */
struct sip_request initreq; /*!< Latest request that opened a new transaction
within this dialog.
NOT the request that opened the dialog
Olle Johansson
committed
*/
int initid; /*!< Auto-congest ID if appropriate (scheduler) */
int waitid; /*!< Wait ID for scheduler after 491 or other delays */
int autokillid; /*!< Auto-kill ID (scheduler) */
enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
struct sip_refer *refer; /*!< REFER: SIP transfer data structure */
enum subscriptiontype subscribed; /*!< SUBSCRIBE: Is this dialog a subscription? */
int stateid; /*!< SUBSCRIBE: ID for devicestate subscriptions */
int laststate; /*!< SUBSCRIBE: Last known extension state */
int dialogver; /*!< SUBSCRIBE: Version for subscription dialog-info */
struct ast_dsp *vad; /*!< Inband DTMF Detection dsp */
Kevin P. Fleming
committed
struct sip_peer *relatedpeer; /*!< If this dialog is related to a peer, which one
Used in peerpoke, mwi subscriptions */
Olle Johansson
committed
struct sip_registry *registry; /*!< If this is a REGISTER dialog, to which registry */
struct ast_rtp *rtp; /*!< RTP Session */
struct ast_rtp *vrtp; /*!< Video RTP session */
struct ast_rtp *trtp; /*!< Text RTP session */
struct sip_pkt *packets; /*!< Packets scheduled for re-transmission */
Olle Johansson
committed
struct sip_history_head *history; /*!< History of this SIP dialog */
size_t history_entries; /*!< Number of entires in the history */
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
struct sip_invite_param *options; /*!< Options for INVITE */
int autoframing; /*!< The number of Asters we group in a Pyroflax
before strolling to the Grokyzpå
(A bit unsure of this, please correct if
you know more) */
/*! Max entires in the history list for a sip_pvt */
#define MAX_HISTORY_ENTRIES 50
/*!
* 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.
*/
Olle Johansson
committed
static struct sip_pvt *dialoglist = NULL;
/*! \brief Protect the SIP dialog list (of sip_pvt's) */
AST_MUTEX_DEFINE_STATIC(dialoglock);
Steve Murphy
committed
#ifndef DETECT_DEADLOCKS
/*! \brief hide the way the list is locked/unlocked */
static void dialoglist_lock(void)
{
ast_mutex_lock(&dialoglock);
}
static void dialoglist_unlock(void)
{
ast_mutex_unlock(&dialoglock);
}
Steve Murphy
committed
#else
/* we don't want to HIDE the information about where the lock was requested if trying to debug
* deadlocks! So, just make these macros! */
#define dialoglist_lock(x) ast_mutex_lock(&dialoglock)
#define dialoglist_unlock(x) ast_mutex_unlock(&dialoglock)
#endif
/*!
* when we create or delete references, make sure to use these
* functions so we keep track of the refcounts.
* To simplify the code, we allow a NULL to be passed to dialog_unref().
*/
static struct sip_pvt *dialog_ref(struct sip_pvt *p)
{
return p;
}
static struct sip_pvt *dialog_unref(struct sip_pvt *p)
{
return NULL;
}
/*! \brief sip packet - raw format for outbound packets that are sent or scheduled for transmission
* Packets are linked in a list, whose head is in the struct sip_pvt they belong to.
* Each packet holds a reference to the parent struct sip_pvt.
* This structure is allocated in __sip_reliable_xmit() and only for packets that
* require retransmissions.
*/
struct sip_pkt *next; /*!< Next packet in linked list */
int retrans; /*!< Retransmission number */
int method; /*!< SIP method for this packet */
int seqno; /*!< Sequence number */
char is_resp; /*!< 1 if this is a response packet (e.g. 200 OK), 0 if it is a request */
char is_fatal; /*!< non-zero if there is a fatal error */
Olle Johansson
committed
struct sip_pvt *owner; /*!< Owner AST call */
int retransid; /*!< Retransmission ID */
int timer_a; /*!< SIP timer A, retransmission timer */
int timer_t1; /*!< SIP Timer T1, estimated RTT or 500 ms */
int packetlen; /*!< Length of packet */
/*! \brief Structure for SIP user data. User's place calls to us */
struct sip_user {
/* Users who can access various contexts */
Mark Spencer
committed
ASTOBJ_COMPONENTS(struct sip_user);
char secret[80]; /*!< Password */
char md5secret[80]; /*!< Password in md5 */
char context[AST_MAX_CONTEXT]; /*!< Default context for incoming calls */
Kevin P. Fleming
committed
char subscribecontext[AST_MAX_CONTEXT]; /* Default context for subscriptions */
char cid_num[80]; /*!< Caller ID num */
char cid_name[80]; /*!< Caller ID name */
char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */
char language[MAX_LANGUAGE]; /*!< Default language for this user */
Kevin P. Fleming
committed
char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */
char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */
char useragent[256]; /*!< User agent in SIP request */
struct ast_codec_pref prefs; /*!< codec prefs */
ast_group_t callgroup; /*!< Call group */
ast_group_t pickupgroup; /*!< Pickup Group */
unsigned int sipoptions; /*!< Supported SIP options */
struct ast_flags flags[2]; /*!< SIP_ flags */
/* things that don't belong in flags */
char is_realtime; /*!< this is a 'realtime' user */
int amaflags; /*!< AMA flags for billing */
int callingpres; /*!< Calling id presentation */
int capability; /*!< Codec capability */
int inUse; /*!< Number of calls in use */
int call_limit; /*!< Limit of concurrent calls */
enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */
struct ast_ha *ha; /*!< ACL setting */
struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
int maxcallbitrate; /*!< Maximum Bitrate for a video call */
int autoframing;
Russell Bryant
committed
/*!
* \brief A peer's mailbox
*
* We could use STRINGFIELDS here, but for only two strings, it seems like
* too much effort ...
*/
struct sip_mailbox {
char *mailbox;
char *context;
/*! Associated MWI subscription */
struct ast_event_sub *event_sub;
AST_LIST_ENTRY(sip_mailbox) entry;
};
/*! \brief Structure for SIP peer data, we place calls to peers if registered or fixed IP address (host) */
/* XXX field 'name' must be first otherwise sip_addrcmp() will fail */
ASTOBJ_COMPONENTS(struct sip_peer); /*!< name, refcount, objflags, object pointers */
/*!< peer->name is the unique name of this object */
char secret[80]; /*!< Password */
char md5secret[80]; /*!< Password in MD5 */
struct sip_auth *auth; /*!< Realm authentication list */
char context[AST_MAX_CONTEXT]; /*!< Default context for incoming calls */
char subscribecontext[AST_MAX_CONTEXT]; /*!< Default context for subscriptions */
char username[80]; /*!< Temporary username until registration */
char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
int amaflags; /*!< AMA Flags (for billing) */
char tohost[MAXHOSTNAMELEN]; /*!< If not dynamic, IP address */
char regexten[AST_MAX_EXTENSION]; /*!< Extension to register (if regcontext is used) */
char fromuser[80]; /*!< From: user when calling this peer */
char fromdomain[MAXHOSTNAMELEN]; /*!< From: domain when calling this peer */
char fullcontact[256]; /*!< Contact registered with us (not in sip.conf) */
char cid_num[80]; /*!< Caller ID num */
char cid_name[80]; /*!< Caller ID name */
int callingpres; /*!< Calling id presentation */
int inUse; /*!< Number of calls in use */
int inRinging; /*!< Number of calls ringing */
int onHold; /*!< Peer has someone on hold */
int call_limit; /*!< Limit of concurrent calls */
int busy_level; /*!< Level of active channels where we signal busy */
enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */
char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/
char language[MAX_LANGUAGE]; /*!< Default language for prompts */
Kevin P. Fleming
committed
char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */
char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */
char useragent[256]; /*!< User agent in SIP request (saved from registration) */
struct ast_codec_pref prefs; /*!< codec prefs */
unsigned int sipoptions; /*!< Supported SIP options */
struct ast_flags flags[2]; /*!< SIP_ flags */
Russell Bryant
committed
/*! Mailboxes that this peer cares about */
AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes;
/* things that don't belong in flags */
char is_realtime; /*!< this is a 'realtime' peer */
char rt_fromcontact; /*!< P: copy fromcontact from realtime */
char host_dynamic; /*!< P: Dynamic Peers register with Asterisk */
char selfdestruct; /*!< P: Automatic peers need to destruct themselves */
int expire; /*!< When to expire this peer registration */
int capability; /*!< Codec capability */
int rtptimeout; /*!< RTP timeout */
int rtpholdtimeout; /*!< RTP Hold Timeout */
int rtpkeepalive; /*!< Send RTP packets for keepalive */
ast_group_t callgroup; /*!< Call group */
ast_group_t pickupgroup; /*!< Pickup group */
struct sip_proxy *outboundproxy; /*!< Outbound proxy for this peer */
struct ast_dnsmgr_entry *dnsmgr;/*!< DNS refresh manager for peer */
struct sockaddr_in addr; /*!< IP address of peer */
int maxcallbitrate; /*!< Maximum Bitrate for a video call */
struct sip_pvt *call; /*!< Call pointer */
int pokeexpire; /*!< When to expire poke (qualify= checking) */
int lastms; /*!< How long last response took (in ms), or -1 for no response */
int maxms; /*!< Max ms we will accept for the host to be up, 0 to not monitor */
Russell Bryant
committed
int qualifyfreq; /*!< Qualification: How often to check for the host to be up */
struct timeval ps; /*!< Time for sending SIP OPTION in sip_pke_peer() */
struct sockaddr_in defaddr; /*!< Default IP address, used until registration */
struct ast_ha *ha; /*!< Access control list */
struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
Kevin P. Fleming
committed
struct sip_pvt *mwipvt; /*!< Subscription for MWI */
int autoframing;
Olle Johansson
committed
int timer_t1; /*!< The maximum T1 value for the peer */
int timer_b; /*!< The maximum timer B (transaction timeouts) */
/*! \brief Registrations with other SIP proxies
* Created by sip_register(), the entry is linked in the 'regl' list,
* and never deleted (other than at 'sip reload' or module unload times).
* The entry always has a pending timeout, either waiting for an ACK to
* the REGISTER message (in which case we have to retransmit the request),
* or waiting for the next REGISTER message to be sent (either the initial one,
* or once the previously completed registration one expires).
* The registration can be in one of many states, though at the moment
* the handling is a bit mixed.
* Note that the entire evolution of sip_registry (transmissions,
* incoming packets and timeouts) is driven by one single thread,
* do_monitor(), so there is almost no synchronization issue.
* The only exception is the sip_pvt creation/lookup,
* as the dialoglist is also manipulated by other threads.
*/
Mark Spencer
committed
ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(callid); /*!< Global Call-ID */
AST_STRING_FIELD(realm); /*!< Authorization realm */
AST_STRING_FIELD(nonce); /*!< Authorization nonce */
AST_STRING_FIELD(opaque); /*!< Opaque nonsense */
AST_STRING_FIELD(qop); /*!< Quality of Protection, since SIP wasn't complicated enough yet. */
AST_STRING_FIELD(domain); /*!< Authorization domain */
AST_STRING_FIELD(username); /*!< Who we are registering as */
AST_STRING_FIELD(authuser); /*!< Who we *authenticate* as */
AST_STRING_FIELD(hostname); /*!< Domain or host we register to */
AST_STRING_FIELD(secret); /*!< Password in clear text */
AST_STRING_FIELD(md5secret); /*!< Password in md5 */
Olle Johansson
committed
AST_STRING_FIELD(callback); /*!< Contact extension */
AST_STRING_FIELD(random);
);
int portno; /*!< Optional port override */
int expire; /*!< Sched ID of expiration */
Olle Johansson
committed
int expiry; /*!< Value to use for the Expires header */
int regattempts; /*!< Number of attempts (since the last success) */
int timeout; /*!< sched id of sip_reg_timeout */
int refresh; /*!< How often to refresh */
Olle Johansson
committed
struct sip_pvt *call; /*!< create a sip_pvt structure for each outbound "registration dialog" in progress */
enum sipregistrystate regstate; /*!< Registration state (see above) */
Tilghman Lesher
committed
struct timeval regtime; /*!< Last successful registration time */
int callid_valid; /*!< 0 means we haven't chosen callid for this registry yet. */
unsigned int ocseq; /*!< Sequence number we got to for REGISTERs for this registry */
struct sockaddr_in us; /*!< Who the server thinks we are */
int noncecount; /*!< Nonce-count */
char lastmsg[256]; /*!< Last Message sent/received */
/* --- Linked lists of various objects --------*/
/*! \brief The user list: Users and friends */
static struct ast_user_list {
Mark Spencer
committed
ASTOBJ_CONTAINER_COMPONENTS(struct sip_user);
/*! \brief The peer list: Peers and Friends */
static struct ast_peer_list {
Mark Spencer
committed
ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer);
/*! \brief The register list: Other SIP proxies we register with and place calls to */
static struct ast_register_list {
Mark Spencer
committed
ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
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 list for realm authentication
* \todo Move the sip_auth list to AST_LIST */
static struct sip_auth *authl = NULL;
/* --- Sockets and networking --------------*/
/*! \brief Main socket for SIP communication.
* sipsock is shared between the manager thread (which handles reload
* requests), the io handler (sipsock_read()) and the user routines that
* issue 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;
static struct sockaddr_in bindaddr; /*!< 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.
*/
static struct sockaddr_in internip;
/*! \brief our external IP address/port for SIP sessions.
* externip.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 "externip = 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;
*
* + with "stunaddr = host[:port]" we run queries every externrefresh seconds
* to the specified server, and store the result in externip.
*
* Other variables (externhost, externexpire, externrefresh) are used
* to support the above functions.
*/
static struct sockaddr_in externip; /*!< External 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 */
Mark Spencer
committed
static int externrefresh = 10;
static struct sockaddr_in stunaddr; /*!< stun server address */
/*! \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 struct sockaddr_in debugaddr;
static struct ast_config *notify_types; /*!< 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, int format, void *data, int *cause);
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);
Olle Johansson
committed
/*--- Transmitting responses and requests */
static int sipsock_read(int *id, int fd, short events, void *ignore);
Olle Johansson
committed
static int __sip_xmit(struct sip_pvt *p, char *data, int len);
static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod);
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_sip_request(struct sip_pvt *p, struct sip_request *req);
static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, 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);
static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
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_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, int 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_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version);
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);
Mark Spencer
committed
static int transmit_message_with_text(struct sip_pvt *p, const char *text);
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, char *vmexten);
static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
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);
static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req);
static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only);
Olle Johansson
committed
/*--- Dialog management */
static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
int useglobal_nat, const int intended_method);
static int __sip_autodestruct(const void *data);
Olle Johansson
committed
static void sip_scheddestroy(struct sip_pvt *p, int ms);
static void sip_cancel_destroy(struct sip_pvt *p);
static struct sip_pvt *sip_destroy(struct sip_pvt *p);
static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist);
Olle Johansson
committed
static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
Olle Johansson
committed
static void __sip_pretend_ack(struct sip_pvt *p);
Olle Johansson
committed
static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
static int auto_congest(const void *arg);
Olle Johansson
committed
static int update_call_counter(struct sip_pvt *fup, int event);
static int hangup_sip2cause(int cause);
static const char *hangup_cause2sip(int cause);
static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, 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 sockaddr_in *sin,
struct sip_request *req, 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);
static int sip_sipredirect(struct sip_pvt *p, const char *dest);
Olle Johansson
committed
/*--- Codec handling / SDP */
static void try_suggested_sip_codec(struct sip_pvt *p);
static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
static const char *get_sdp(struct sip_request *req, const char *name);
static int find_sdp(struct sip_request *req);
Olle Johansson
committed
static int process_sdp(struct sip_pvt *p, struct sip_request *req);
static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
struct ast_str **m_buf, struct ast_str **a_buf,
int debug, int *min_packet_size);
Olle Johansson
committed
static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
struct ast_str **m_buf, struct ast_str **a_buf,
Olle Johansson
committed
int debug);
Olle Johansson
committed
static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p);
static void do_setnat(struct sip_pvt *p, int natflags);
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,
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, char *uri, enum xmittype reliable,
struct sockaddr_in *sin, struct sip_peer **authpeer);
static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin);
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 struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno);
static int clear_realm_authentication(struct sip_auth *authlist); /* Clear realm authentication list (at reload) */
static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);
Olle Johansson
committed
/*--- Misc functions */
static int sip_do_reload(enum channelreloadreason reason);
static int reload_config(enum channelreloadreason reason);
static int expire_register(const void *data);
static void *do_monitor(void *data);
Olle Johansson
committed
static int restart_monitor(void);
static int sip_addrcmp(char *name, struct sockaddr_in *sin); /* Support for peer matching */
static int sip_refer_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);
/*--- Device monitoring and Device/extension state/event handling */
static int cb_extensionstate(char *context, char* exten, int 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);
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 *);
/*--- 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 const char *nat2str(int nat) attribute_const;
static int peer_status(struct sip_peer *peer, char *status, int statuslen);
static char *sip_show_users(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 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_show_user(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);
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_user(const char *word, int state, int flags2);
static char *complete_sip_show_user(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);
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, char *arg);
static char *sip_do_debug_peer(int fd, char *arg);
static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_do_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_no_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static int sip_dtmfmode(struct ast_channel *chan, void *data);
static int sip_addheader(struct ast_channel *chan, void *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 acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen);
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 */
Olle Johansson
committed
static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
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 *temp_peer(const char *name);
static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime);
Olle Johansson
committed
static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime);
static int update_call_counter(struct sip_pvt *fup, int event);
static void sip_destroy_peer(struct sip_peer *peer);
static void sip_destroy_user(struct sip_user *user);
static int sip_poke_peer(struct sip_peer *peer);
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 struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime);
static struct sip_user *find_user(const char *name, int realtime);
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);
Olle Johansson
committed
/* Realtime device support */
static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey);
static struct sip_user *realtime_user(const char *username);
static void update_peer(struct sip_peer *p, int expiry);
static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername);
Olle Johansson
committed
static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
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(struct in_addr *them, struct sockaddr_in *us);
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);
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_sip_options(struct sip_pvt *pvt, const char *supported);
static void parse_request(struct sip_request *req);
static const char *get_header(const struct sip_request *req, const char *name);
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 char *get_in_brackets(char *tmp);
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 int lws2sws(char *msgbuf, int len);
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);
static char *get_calleridname(const char *input, char *output, size_t outputsize);
static int get_rpid_num(const char *input, char *output, int maxlen);
static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq);
static int get_destination(struct sip_pvt *p, struct sip_request *oreq);
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);
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 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);
static int init_resp(struct sip_request *resp, const char *msg);
static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req);
Olle Johansson
committed
static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
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);
static char *generate_random_string(char *buf, size_t size);
static void build_callid_pvt(struct sip_pvt *pvt);
static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
static void make_our_tag(char *tagbuf, size_t len);
static int add_header(struct sip_request *req, const char *var, const char *value);
static int add_header_contentLength(struct sip_request *req, int len);
static int add_line(struct sip_request *req, const char *line);
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);
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);
static void build_rpid(struct sip_pvt *p);
/*------Request handling functions */
static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock);
static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, 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 sockaddr_in *sin, 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);
static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, 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);
static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin);
static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
/*------Response handling functions */
static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active);
Joshua Colp
committed
static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
static enum ast_rtp_get_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
static int sip_get_codec(struct ast_channel *chan);
static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
/*------ T38 Support --------- */
static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite);
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);
/*! \brief Definition of this channel for PBX channel registration */
static const struct ast_channel_tech sip_tech = {
.description = "Session Initiation Protocol (SIP)",
.capabilities = AST_FORMAT_AUDIO_MASK, /* all audio formats */
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_bridge, /* XXX chan unlocked ? */
Joshua Colp
committed
.early_bridge = ast_rtp_early_bridge,
.send_text = sip_sendtext, /* called with chan locked */
.func_channel_read = acf_channel_read,
};
/*! \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.
*/
static struct ast_channel_tech sip_tech_info;
/* wrapper macro to tell whether t points to one of the sip_tech descriptors */
#define IS_SIP_TECH(t) ((t) == &sip_tech || (t) == &sip_tech_info)
/*! \brief map from an integer value to a string.
* If no match is found, return errorstring
*/
static const char *map_x_s(const struct _map_x_s *table, int x, const char *errorstring)
{
const struct _map_x_s *cur;
for (cur = table; cur->s; cur++)
if (cur->x == x)
return cur->s;
return errorstring;
}
/*! \brief map from a string to an integer value, case insensitive.
* If no match is found, return errorvalue.
*/
static int map_s_x(const struct _map_x_s *table, const char *s, int errorvalue)
{
const struct _map_x_s *cur;
for (cur = table; cur->s; cur++)
if (!strcasecmp(cur->s, s))
return cur->x;
return errorvalue;
}
/*! \brief Interface structure with callbacks used to connect to RTP module */
static struct ast_rtp_protocol sip_rtp = {
.type = "SIP",
.get_rtp_info = sip_get_rtp_peer,
.get_vrtp_info = sip_get_vrtp_peer,
.get_trtp_info = sip_get_trtp_peer,
.set_rtp_peer = sip_set_rtp_peer,
.get_codec = sip_get_codec,
Steve Murphy
committed
#define sip_pvt_lock(x) ast_mutex_lock(&x->pvt_lock)
#define sip_pvt_unlock(x) ast_mutex_unlock(&x->pvt_lock)
/*!
* helper functions to unreference various types of objects.
* By handling them this way, we don't have to declare the
* destructor on each call, which removes the chance of errors.
*/
static void unref_peer(struct sip_peer *peer)
{
ASTOBJ_UNREF(peer, sip_destroy_peer);
}
static void unref_user(struct sip_user *user)
{
ASTOBJ_UNREF(user, sip_destroy_user);
}
static void *registry_unref(struct sip_registry *reg)
ast_debug(3, "SIP Registry %s: refcount now %d\n", reg->hostname, reg->refcount - 1);
ASTOBJ_UNREF(reg, sip_registry_destroy);
Olle Johansson
committed
/*! \brief Add object reference to SIP registry */
static struct sip_registry *registry_addref(struct sip_registry *reg)
{
ast_debug(3, "SIP Registry %s: refcount now %d\n", reg->hostname, reg->refcount + 1);
Olle Johansson
committed
return ASTOBJ_REF(reg); /* Add pointer to registry in packet */
}
/*! \brief Interface structure with callbacks used to connect to UDPTL module*/
static struct ast_udptl_protocol sip_udptl = {
type: "SIP",
get_udptl_info: sip_get_udptl_peer,
set_udptl_peer: sip_set_udptl_peer,
};
/*! \brief Append to SIP dialog history
\return Always returns 0 */
#define append_history(p, event, fmt , args... ) append_history_full(p, "%-15s " fmt, event, ## args)
static void append_history_full(struct sip_pvt *p, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
/*! \brief Convert transfer status to string */
static const char *referstatus2str(enum referstatus rstatus)
return map_x_s(referstatusstrings, rstatus, "");
}
Olle Johansson
committed
/*! \brief Initialize the initital request packet in the pvt structure.
This packet is used for creating replies and future requests in
a dialog */
Kevin P. Fleming
committed
static void initialize_initreq(struct sip_pvt *p, struct sip_request *req)
Olle Johansson
committed
{
if (p->initreq.headers)
ast_debug(1, "Initializing already initialized SIP dialog %s (presumably reinvite)\n", p->callid);
else
ast_debug(1, "Initializing initreq for method %s - callid %s\n", sip_methods[req->method].text, p->callid);
Olle Johansson
committed
/* Use this as the basis */
copy_request(&p->initreq, req);
parse_request(&p->initreq);
if (req->debug)
Olle Johansson
committed
ast_verbose("Initreq: %d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
Olle Johansson
committed
}
/*! \brief Encapsulate setting of SIP_ALREADYGONE to be able to trace it with debugging */
static void sip_alreadygone(struct sip_pvt *dialog)
{
ast_debug(3, "Setting SIP_ALREADYGONE on dialog %s\n", dialog->callid);
dialog->alreadygone = 1;
/*! Resolve DNS srv name or host name in a sip_proxy structure */
static int proxy_update(struct sip_proxy *proxy)
{