Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:19 2007

Asterisk developer's documentation :: Codename Pineapple


chan_sip3.c File Reference


Detailed Description

Implementation of Session Initiation Protocol Version 3 of chan_sip.

Author:
Mark Spencer <markster@digium.com>

Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)

See Also: Implementation of RFC 3261 - without S/MIME, TCP and TLS support Configuration file sip.conf

Todo:
SIP over TCP

SIP over TLS

Better support of forking

VIA branch tag transaction checking

Transaction support

Definition in file chan_sip3.c.

#include "asterisk.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <regex.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/udptl.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
#include "asterisk/translate.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/dsp.h"
#include "asterisk/features.h"
#include "asterisk/srv.h"
#include "asterisk/astdb.h"
#include "asterisk/causes.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/astobj.h"
#include "asterisk/dnsmgr.h"
#include "asterisk/devicestate.h"
#include "asterisk/linkedlists.h"
#include "asterisk/stringfields.h"
#include "asterisk/monitor.h"
#include "asterisk/localtime.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/compiler.h"
#include "sip3/sip3.h"
#include "sip3/sip3funcs.h"

Include dependency graph for chan_sip3.c:

Go to the source code of this file.

Defines

#define CHAN_SIP3_MAIN
#define GNURK
#define SIPLABEL   sip3

Functions

GNURK int add_t38_sdp (struct sip_request *resp, struct sip_dialog *p)
 Add T.38 Session Description Protocol message.
static int add_vidupdate (struct sip_request *req)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Session Initiation Protocol, chan_sip3 version (SIP)",.load=load_module,.unload=unload_module,.reload=reload,)
 AST_MUTEX_DEFINE_STATIC (sip_reload_lock)
 Make sure we don't reload twice at the same time.
GNURK void ast_quiet_chan (struct ast_channel *chan)
 Turn off generator data XXX Does this function belong in the SIP channel?
static int auto_congest (void *nothing)
 Scheduled congestion on a call.
static void build_route (struct sip_dialog *p, struct sip_request *req, int backwards)
 Build route list from Record-Route header.
static int cb_extensionstate (char *context, char *exten, int state, void *data)
 Callback for the devicestate notification (SUBSCRIBE) support subsystem.
static void check_pendings (struct sip_dialog *p)
 Check pending actions on SIP call.
static int check_user (struct sip_dialog *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin)
 Find user If we get a match, this will add a reference pointer to the user object in ASTOBJ, that needs to be unreferenced.
static enum check_auth_result check_user_full (struct sip_dialog *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin, struct sip_device **authpeer)
 Check if matching user or peer is defined Match user on From: user name and peer on IP/port This is used on first invite (not re-invites) and subscribe requests.
static void check_via (struct sip_dialog *p, struct sip_request *req)
 check Via: header for hostname, port and rport request/answer
GNURK int create_addr (struct sip_dialog *dialog, const char *username, char *domain, const char *device)
 create address structure from peer name Or, if peer not found, find it in the global DNS returns TRUE (-1) on failure, FALSE on success
static int create_addr_from_peer (struct sip_dialog *dialog, struct sip_device *device)
 Create address structure from device reference. return -1 on error, 0 on success.
GNURK void do_setnat (struct sip_dialog *dialog, int natflags)
 Set nat mode on the various media streams.
void free_old_route (struct sip_route *route)
 Remove route from route list.
static int func_header_read (struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
 Read SIP header (dialplan function).
static int function_sipchaninfo_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 ${SIPCHANINFO()} Dialplan function - reads sip channel data
static int function_sippeer (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 ${SIPPEER()} Dialplan function - reads peer data
static int get_also_info (struct sip_dialog *p, struct sip_request *oreq)
 Call transfer support (old way, deprecated by the IETF)--.
static int get_msg_text (char *buf, int len, struct sip_request *req)
 Get text out of a SIP MESSAGE packet.
GNURK struct sip_dialogget_sip_dialog_byid_locked (const char *callid, const char *totag, const char *fromtag)
 Lock dialog list lock and find matching pvt lock
  • Their tag is fromtag, our tag is to-tag
  • This means that in some transactions, totag needs to be their tag :-) depending upon the direction.

static int handle_invite_replaces (struct sip_dialog *p, struct sip_request *req, int debug, struct sockaddr_in *sin)
 Handle the transfer part of INVITE with a replaces: header, meaning a target pickup or an attended transfer.
GNURK int handle_request (struct sip_dialog *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock)
 Handle incoming SIP requests (methods).
static int handle_request_bye (struct sip_dialog *p, struct sip_request *req)
 Handle incoming BYE request.
static int handle_request_cancel (struct sip_dialog *p, struct sip_request *req)
 Handle incoming CANCEL request.
static void handle_request_info (struct sip_dialog *p, struct sip_request *req)
 Receive SIP INFO Message.
static int handle_request_invite (struct sip_dialog *p, struct sip_request *req, int debug, struct sockaddr_in *sin, int *recount, char *e)
 Handle incoming INVITE request.
static int handle_request_message (struct sip_dialog *p, struct sip_request *req)
 Handle incoming MESSAGE request.
static int handle_request_notify (struct sip_dialog *p, struct sip_request *req, struct sockaddr_in *sin, char *e)
 Handle incoming notifications.
static int handle_request_options (struct sip_dialog *p, struct sip_request *req)
 Handle incoming OPTIONS request.
static int handle_request_register (struct sip_dialog *p, struct sip_request *req, struct sockaddr_in *sin, char *e)
 Handle incoming REGISTER request.
static int handle_request_subscribe (struct sip_dialog *p, struct sip_request *req, struct sockaddr_in *sin, char *e)
 Handle incoming SUBSCRIBE request.
static void handle_response (struct sip_dialog *p, int resp, char *rest, struct sip_request *req)
 Handle SIP response in dialogue.
static void handle_response_answer (struct sip_dialog *dialog, struct sip_request *req, int outgoing, int reinvite)
 Handle a positive response to an INVITE - 200 OK.
static void handle_response_bye (struct sip_dialog *dialog, int resp, char *rest, struct sip_request *req)
static void handle_response_invite (struct sip_dialog *p, int resp, char *rest, struct sip_request *req)
 Handle SIP response to INVITE dialogue.
static void handle_response_message (struct sip_dialog *dialog, int resp, char *rest, struct sip_request *req)
static void handle_response_notify (struct sip_dialog *dialog, int resp, char *rest, struct sip_request *req)
static void handle_response_refer (struct sip_dialog *p, int resp, char *rest, struct sip_request *req)
static void list_route (struct sip_route *route)
 List all routes - mostly for debugging.
static int load_module (void)
 load_module: PBX load module - initialization
static int parse_ok_contact (struct sip_dialog *pvt, struct sip_request *req)
 Save contact header for 200 OK on INVITE.
static enum parse_register_result parse_register_contact (struct sip_dialog *pvt, struct sip_device *peer, struct sip_request *req)
 Parse contact header and save registration (peer registration).
static void receive_message (struct sip_dialog *p, struct sip_request *req)
 Receive SIP MESSAGE method messages.
static enum check_auth_result register_verify (struct sip_dialog *p, struct sockaddr_in *sin, struct sip_request *req, char *uri)
 Verify registration of user
  • Registration is done in several steps, first a REGISTER without auth to get a challenge (nonce) then a second one with auth
  • Registration requests are only matched with peers that are marked as "dynamic".

static int reload (void)
 reload: Part of Asterisk module interface
static int set_address_from_contact (struct sip_dialog *pvt)
 Change the other partys IP address based on given contact.
static int sip_addheader (struct ast_channel *chan, void *data)
 Add a SIP header to an outbound INVITE.
static int sip_answer (struct ast_channel *ast)
 sip_answer: Answer SIP call , send 200 OK on Invite Part of PBX interface
static int sip_call (struct ast_channel *ast, char *dest, int timeout)
 Initiate SIP call from PBX used from the dial() application.
GNURK int sip_debug_test_pvt (struct sip_dialog *p)
 Test PVT for debugging output.
static int sip_devicestate (void *data)
 Part of PBX channel interface.
GNURK int sip_do_reload ()
 Reload module.
static int sip_dtmfmode (struct ast_channel *chan, void *data)
 Set the DTMFmode for an outbound SIP call (application).
GNURK void sip_dump_history (struct sip_dialog *dialog)
 Dump SIP history to debug log file at end of lifespan for SIP dialog.
static int sip_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
 sip_fixup: Fix up a channel: If a channel is consumed, this is called. Basically update any ->owner links :: PBX interface
static int sip_handle_t38_reinvite (struct ast_channel *chan, struct sip_dialog *pvt, int reinvite)
static int sip_hangup (struct ast_channel *ast)
 sip_hangup: Hangup SIP call Part of PBX interface, called from ast_hangup
static int sip_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
 Play indication to user :: PBX interface With SIP a lot of indications is sent as messages, letting the device play the indication - busy signal, congestion etc.
static struct ast_channelsip_new (struct sip_dialog *dialog, int state, const char *title)
 Initiate a call in the SIP channel :: PBX interface.
GNURK int sip_notify (int fd, int argc, char *argv[])
 Cli command to send SIP notify to peer.
GNURK void sip_peer_hold (struct sip_dialog *p, int hold)
 Change onhold state of a peer using a pvt structure.
GNURK int sip_prune_realtime (int fd, int argc, char *argv[])
 Remove temporary realtime objects from memory (CLI).
GNURK int sip_reload (int fd)
 Force reload of module from cli.
int sip_reload_check ()
static struct ast_channelsip_request_call (const char *type, int format, void *data, int *cause)
GNURK int sip_send_mwi_to_peer (struct sip_device *peer)
 Send message waiting indication to alert peer that they've got voicemail.
static int sip_senddigit_begin (struct ast_channel *ast, char digit)
 Start sending DTMF character on SIP channel within one call, we're able to transmit in many methods simultaneously.
static int sip_senddigit_end (struct ast_channel *ast, char digit, unsigned int duration)
 Send DTMF character on SIP channel within one call, we're able to transmit in many methods simultaneously.
static int sip_sendtext (struct ast_channel *ast, const char *text)
 Send SIP MESSAGE text within a call Called from PBX core sendtext() application.
static int sip_sipredirect (struct sip_dialog *p, const char *dest)
 Transfer call before connect with a 302 redirect.
static int sip_transfer (struct ast_channel *ast, const char *dest)
 Transfer SIP call :: PBX interface.
static int sip_write (struct ast_channel *ast, struct ast_frame *frame)
 Send frame to media channel (rtp) :: PBX interface.
static int t38_get_rate (int t38cap)
 Get Max T.38 Transmission rate from T38 capabilities.
static char * terminate_uri (char *uri)
GNURK void try_suggested_sip_codec (struct sip_dialog *p)
 Try setting codec suggested by the SIP_CODEC channel variable.
static int unload_module (void)
GNURK int update_call_counter (struct sip_dialog *fup, int event)
 update_call_counter: Handle call_limit for SIP users Setting a call-limit will cause calls above the limit not to be accepted.
static int write_media_frame (struct ast_channel *ast, struct sip_dialog *p, struct ast_frame *frame, struct ast_rtp *mediartp)

Variables

static char * app_dtmfmode = "SIPDtmfMode"
static char * app_sipaddheader = "SIPAddHeader"
static char * descrip_dtmfmode = "SIPDtmfMode(inband|info|rfc2833): Changes the dtmfmode for a SIP call\n"
static char * descrip_sipaddheader
sip_dialogdialoglist = NULL
expiry_times expiry
 various expiry times for registrations
sip_globals global
 Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical.
io_contextio
ast_confignotify_types
sched_contextsched
static struct ast_custom_function sip_header_function
static int sip_reloading = FALSE
static enum channelreloadreason sip_reloadreason
static const struct ast_channel_tech sip_tech
 Definition of this channel for PBX channel registration.
static const struct ast_channel_tech sip_tech_info
 This version of the sip channel tech has no send_digit_begin callback. This is for use with channels using SIP INFO DTMF so that the core knows that the channel doesn't want DTMF BEGIN frames.
static struct ast_custom_function sipchaninfo_function
 Structure to declare a dialplan function: SIPCHANINFO.
channel_counters sipcounters = { 0, 0, 0, 0, 0, 0, 0, 0}
ast_custom_function sippeer_function
 Structure to declare a dialplan function: SIPPEER.
static char * synopsis_dtmfmode = "Change the dtmfmode for a SIP call"
static char * synopsis_sipaddheader = "Add a SIP header to the outbound call"


Define Documentation

#define CHAN_SIP3_MAIN
 

Definition at line 406 of file chan_sip3.c.

#define GNURK
 

Definition at line 410 of file chan_sip3.c.

#define SIPLABEL   sip3
 

Definition at line 473 of file chan_sip3.c.


Function Documentation

GNURK int add_t38_sdp struct sip_request resp,
struct sip_dialog p
 

Add T.38 Session Description Protocol message.

Definition at line 1749 of file chan_sip3.c.

References add_header(), add_header_contentLength(), add_line(), ast_build_string(), ast_inet_ntoa(), ast_log(), ast_udptl_get_local_max_datagram(), ast_udptl_get_us(), t38properties::capability, debug(), t38properties::jointcapability, sip_dialog::lastrtprx, sip_dialog::lastrtptx, len, LOG_DEBUG, LOG_WARNING, sip_dialog::ourip, t38properties::peercapability, s, sip_dialog::sessionid, sip_dialog::sessionversion, sip_debug_test_pvt(), sip_dialog::t38, t38_get_rate(), T38FAX_FILL_BIT_REMOVAL, T38FAX_RATE_MANAGEMENT_LOCAL_TCF, T38FAX_TRANSCODING_JBIG, T38FAX_TRANSCODING_MMR, T38FAX_UDP_EC_NONE, T38FAX_UDP_EC_REDUNDANCY, T38FAX_VERSION, T38FAX_VERSION_0, T38FAX_VERSION_1, sip_dialog::udptl, and sip_dialog::udptlredirip.

01750 {
01751    int len = 0;
01752    int x = 0;
01753    struct sockaddr_in udptlsin;
01754    char v[256] = "";
01755    char s[256] = "";
01756    char o[256] = "";
01757    char c[256] = "";
01758    char t[256] = "";
01759    char m_modem[256];
01760    char a_modem[1024];
01761    char *m_modem_next = m_modem;
01762    size_t m_modem_left = sizeof(m_modem);
01763    char *a_modem_next = a_modem;
01764    size_t a_modem_left = sizeof(a_modem);
01765    struct sockaddr_in udptldest = { 0, };
01766    int debug;
01767    
01768    debug = sip_debug_test_pvt(p);
01769    len = 0;
01770    if (!p->udptl) {
01771       ast_log(LOG_WARNING, "No way to add SDP without an UDPTL structure\n");
01772       return -1;
01773    }
01774    
01775    if (!p->sessionid) {
01776       p->sessionid = getpid();
01777       p->sessionversion = p->sessionid;
01778    } else
01779       p->sessionversion++;
01780    
01781    /* Our T.38 end is */
01782    ast_udptl_get_us(p->udptl, &udptlsin);
01783    
01784    /* Determine T.38 UDPTL destination */
01785    if (p->udptlredirip.sin_addr.s_addr) {
01786       udptldest.sin_port = p->udptlredirip.sin_port;
01787       udptldest.sin_addr = p->udptlredirip.sin_addr;
01788    } else {
01789       udptldest.sin_addr = p->ourip;
01790       udptldest.sin_port = udptlsin.sin_port;
01791    }
01792    
01793    if (debug) 
01794       ast_log(LOG_DEBUG, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip), ntohs(udptlsin.sin_port));
01795    
01796    /* We break with the "recommendation" and send our IP, in order that our
01797       peer doesn't have to ast_gethostbyname() us */
01798    
01799    if (debug) {
01800       ast_log(LOG_DEBUG, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
01801          p->t38.capability,
01802          p->t38.peercapability,
01803          p->t38.jointcapability);
01804    }
01805    snprintf(v, sizeof(v), "v=0\r\n");
01806    snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(udptldest.sin_addr));
01807    snprintf(s, sizeof(s), "s=session\r\n");
01808    snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(udptldest.sin_addr));
01809    snprintf(t, sizeof(t), "t=0 0\r\n");
01810    ast_build_string(&m_modem_next, &m_modem_left, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
01811    
01812    if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
01813       ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVersion:0\r\n");
01814    if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
01815       ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVersion:1\r\n");
01816    if ((x = t38_get_rate(p->t38.jointcapability)))
01817       ast_build_string(&a_modem_next, &a_modem_left, "a=T38MaxBitRate:%d\r\n",x);
01818    ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxFillBitRemoval:%d\r\n", (p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) ? 1 : 0);
01819    ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingMMR:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_MMR) ? 1 : 0);
01820    ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingJBIG:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) ? 1 : 0);
01821    ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
01822    x = ast_udptl_get_local_max_datagram(p->udptl);
01823    ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxBuffer:%d\r\n",x);
01824    ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxDatagram:%d\r\n",x);
01825    if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
01826       ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
01827     len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m_modem) + strlen(a_modem);
01828    add_header(resp, "Content-Type", "application/sdp");
01829    add_header_contentLength(resp, len);
01830    add_line(resp, v);
01831    add_line(resp, o);
01832    add_line(resp, s);
01833    add_line(resp, c);
01834    add_line(resp, t);
01835    add_line(resp, m_modem);
01836    add_line(resp, a_modem);
01837    
01838    /* Update lastrtprx when we send our SDP */
01839    p->lastrtprx = p->lastrtptx = time(NULL);
01840    
01841    return 0;
01842 }

static int add_vidupdate struct sip_request req  )  [static]
 

AST_MODULE_INFO ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Session Initiation   Protocol,
chan_sip3 version(SIP)"  ,
load = load_module,
unload = unload_module,
reload = reload
 

AST_MUTEX_DEFINE_STATIC sip_reload_lock   ) 
 

Make sure we don't reload twice at the same time.

GNURK void ast_quiet_chan struct ast_channel chan  ) 
 

Turn off generator data XXX Does this function belong in the SIP channel?

Definition at line 4034 of file chan_sip3.c.

References ast_channel::_state, ast_deactivate_generator(), AST_STATE_UP, and ast_channel::generatordata.

04035 {
04036    if (chan && chan->_state == AST_STATE_UP) {
04037       if (chan->generatordata)
04038          ast_deactivate_generator(chan);
04039    }
04040 }

static int auto_congest void *  nothing  )  [static]
 

Scheduled congestion on a call.

Definition at line 881 of file chan_sip3.c.

References append_history, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_CONGESTION, ast_log(), ast_queue_control(), dialog_lock(), FALSE, sip_dialog::initid, LOG_NOTICE, sip_dialog::owner, and TRUE.

00882 {
00883    struct sip_dialog *dialog = nothing;
00884 
00885    dialog_lock(dialog, TRUE);
00886    dialog->initid = -1;
00887    if (dialog->owner) {
00888       /* XXX fails on possible deadlock */
00889       if (!ast_channel_trylock(dialog->owner)) {
00890          ast_log(LOG_NOTICE, "Auto-congesting %s\n", dialog->owner->name);
00891          append_history(dialog, "Cong", "Auto-congesting (timer)");
00892          ast_queue_control(dialog->owner, AST_CONTROL_CONGESTION);
00893          ast_channel_unlock(dialog->owner);
00894       }
00895    }
00896    dialog_lock(dialog, FALSE);
00897    return 0;
00898 }

static void build_route struct sip_dialog p,
struct sip_request req,
int  backwards
[static]
 

Build route list from Record-Route header.

Definition at line 2107 of file chan_sip3.c.

References __get_header(), ast_log(), ast_malloc, free_old_route(), sip_route::hop, len, LOG_DEBUG, sip_route::next, option_debug, sip_dialog::route, and sip_dialog::route_persistant.

02108 {
02109    struct sip_route *thishop, *head, *tail;
02110    int start = 0;
02111    int len;
02112    const char *rr, *contact, *c;
02113 
02114    /* Once a persistant route is set, don't fool with it */
02115    if (p->route && p->route_persistant) {
02116       if (option_debug)
02117          ast_log(LOG_DEBUG, "build_route: Retaining previous route: <%s>\n", p->route->hop);
02118       return;
02119    }
02120 
02121    if (p->route) {
02122       free_old_route(p->route);
02123       p->route = NULL;
02124    }
02125    
02126    p->route_persistant = backwards;
02127    
02128    /* Build a tailq, then assign it to p->route when done.
02129     * If backwards, we add entries from the head so they end up
02130     * in reverse order. However, we do need to maintain a correct
02131     * tail pointer because the contact is always at the end.
02132     */
02133    head = NULL;
02134    tail = head;
02135    /* 1st we pass through all the hops in any Record-Route headers */
02136    for (;;) {
02137       /* Each Record-Route header */
02138       rr = __get_header(req, "Record-Route", &start);
02139       if (*rr == '\0')
02140          break;
02141       for (; (rr = strchr(rr, '<')) ; rr += len) { /* Each route entry */
02142          ++rr;
02143          len = strcspn(rr, ">") + 1;
02144          /* Make a struct route */
02145          if ((thishop = ast_malloc(sizeof(*thishop) + len))) {
02146             /* ast_calloc is not needed because all fields are initialized in this block */
02147             ast_copy_string(thishop->hop, rr, len);
02148             if (option_debug > 1)
02149                ast_log(LOG_DEBUG, "build_route: Record-Route hop: <%s>\n", thishop->hop);
02150             /* Link in */
02151             if (backwards) {
02152                /* Link in at head so they end up in reverse order */
02153                thishop->next = head;
02154                head = thishop;
02155                /* If this was the first then it'll be the tail */
02156                if (!tail)
02157                   tail = thishop;
02158             } else {
02159                thishop->next = NULL;
02160                /* Link in at the end */
02161                if (tail)
02162                   tail->next = thishop;
02163                else
02164                   head = thishop;
02165                tail = thishop;
02166             }
02167          }
02168       }
02169    }
02170 
02171    /* Only append the contact if we are dealing with a strict router */
02172    if (!head || (!ast_strlen_zero(head->hop) && strstr(head->hop,";lr") == NULL) ) {
02173       /* 2nd append the Contact: if there is one */
02174       /* Can be multiple Contact headers, comma separated values - we just take the first */
02175       contact = get_header(req, "Contact");
02176       if (!ast_strlen_zero(contact)) {
02177          if (option_debug > 1)
02178             ast_log(LOG_DEBUG, "build_route: Contact hop: %s\n", contact);
02179          /* Look for <: delimited address */
02180          c = strchr(contact, '<');
02181          if (c) {
02182             /* Take to > */
02183             ++c;
02184             len = strcspn(c, ">") + 1;
02185          } else {
02186             /* No <> - just take the lot */
02187             c = contact;
02188             len = strlen(contact) + 1;
02189          }
02190          if ((thishop = ast_malloc(sizeof(*thishop) + len))) {
02191             /* ast_calloc is not needed because all fields are initialized in this block */
02192             ast_copy_string(thishop->hop, c, len);
02193             thishop->next = NULL;
02194             /* Goes at the end */
02195             if (tail)
02196                tail->next = thishop;
02197             else
02198                head = thishop;
02199          }
02200       }
02201    }
02202 
02203    /* Store as new route */
02204    p->route = head;
02205 
02206    /* For debugging dump what we ended up with */
02207    if (sip_debug_test_pvt(p))
02208       list_route(p->route);
02209 }

static int cb_extensionstate char *  context,
char *  exten,
int  state,
void *  data
[static]
 

Callback for the devicestate notification (SUBSCRIBE) support subsystem.

Note:
If you add an "hint" priority to the extension in the dial plan, you will get notifications on device state changes

Definition at line 2234 of file chan_sip3.c.

References append_history, AST_EXTENSION_DEACTIVATED, AST_EXTENSION_REMOVED, ast_extension_state2str(), ast_verbose(), sip_dialog::autokillid, DEFAULT_TRANS_TIMEOUT, FALSE, sip_dialog::laststate, NONE, option_verbose, sip_cancel_destroy(), sip_scheddestroy(), sip_dialog::stateid, sip_dialog::subscribed, transmit_state_notify(), VERBOSE_PREFIX_1, and VERBOSE_PREFIX_2.

02235 {
02236    struct sip_dialog *p = data;
02237 
02238    switch(state) {
02239    case AST_EXTENSION_DEACTIVATED:  /* Retry after a while */
02240    case AST_EXTENSION_REMOVED:   /* Extension is gone */
02241       if (p->autokillid > -1)
02242          sip_cancel_destroy(p);  /* Remove subscription expiry for renewals */
02243       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);  /* Delete subscription in 32 secs */
02244       ast_verbose(VERBOSE_PREFIX_2 "Extension state: Watcher for hint %s %s. Notify User %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", p->peername);
02245       p->stateid = -1;
02246       p->subscribed = NONE;
02247       append_history(p, "Subscribestatus", "%s", state == AST_EXTENSION_REMOVED ? "HintRemoved" : "Deactivated");
02248       break;
02249    default: /* Tell user */
02250       p->laststate = state;
02251       break;
02252    }
02253    transmit_state_notify(p, state, 1, FALSE);
02254 
02255    if (option_verbose > 1)
02256       ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %s for Notify User %s\n", exten, ast_extension_state2str(state), p->peername);
02257    return 0;
02258 }

static void check_pendings struct sip_dialog p  )  [static]
 

Check pending actions on SIP call.

Definition at line 3433 of file chan_sip3.c.

References ast_clear_flag, ast_log(), ast_test_flag, DEFAULT_TRANS_TIMEOUT, FALSE, sip_dialog::flags, option_debug, SIP_BYE, SIP_CAN_BYE, SIP_CANCEL, SIP_NEEDREINVITE, SIP_PENDINGBYE, sip_scheddestroy(), transmit_reinvite_with_sdp(), and transmit_request_with_auth().

03434 {
03435    if (ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
03436       /* if we can't BYE, then this is really a pending CANCEL */
03437       if (!ast_test_flag(&p->flags[0], SIP_CAN_BYE))
03438          transmit_request_with_auth(p, SIP_CANCEL, p->ocseq, 1, 0);
03439          /* Actually don't destroy us yet, wait for the 487 on our original 
03440             INVITE, but do set an autodestruct just in case we never get it. */
03441       else 
03442          transmit_request_with_auth(p, SIP_BYE, 0, 1, 1);
03443       ast_clear_flag(&p->flags[0], SIP_PENDINGBYE);   
03444       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
03445    } else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
03446       if (option_debug)
03447          ast_log(LOG_DEBUG, "Sending pending reinvite on '%s'\n", p->callid);
03448       /* Didn't get to reinvite yet, so do it now */
03449       transmit_reinvite_with_sdp(p, FALSE);
03450       ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE); 
03451    }
03452 }

static int check_user struct sip_dialog p,
struct sip_request req,
int  sipmethod,
char *  uri,
enum xmittype  reliable,
struct sockaddr_in *  sin
[static]
 

Find user If we get a match, this will add a reference pointer to the user object in ASTOBJ, that needs to be unreferenced.

Definition at line 2868 of file chan_sip3.c.

References check_user_full().

02869 {
02870    return check_user_full(p, req, sipmethod, uri, reliable, sin, NULL);
02871 }

static enum check_auth_result check_user_full struct sip_dialog p,
struct sip_request req,
int  sipmethod,
char *  uri,
enum xmittype  reliable,
struct sockaddr_in *  sin,
struct sip_device **  authpeer
[static]
 

Check if matching user or peer is defined Match user on From: user name and peer on IP/port This is used on first invite (not re-invites) and subscribe requests.

Returns:
0 on success, non-zero on failure

Definition at line 2637 of file chan_sip3.c.

References sip_device_extra::accountcode, accountcode, sip_globals::allowguest, sip_device::allowtransfer, sip_device_extra::amaflags, ast_apply_ha(), ast_copy_flags, ast_inet_ntoa(), ast_is_shrinkable_phonenumber(), ast_log(), ast_rtp_codec_setpref(), ast_rtp_destroy(), AST_RTP_DTMF, ast_set_flag, ast_shrink_phone_number(), ast_strdupa, ast_string_field_free, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_uri_decode(), ast_variable_new(), ast_verbose(), AUTH_SUCCESSFUL, sip_device::autoframing, build_contact(),