Codename Pineapple

Home page | Mailing list | Docs

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

Asterisk developer's documentation :: Codename Pineapple


sip3_dialog.c File Reference


Detailed Description

Various SIP dialog handlers Version 3 of chan_sip.

Author:
Mark Spencer <markster@digium.com>

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

See Also:

Definition in file sip3_dialog.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/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 "asterisk/threadstorage.h"
#include "sip3.h"
#include "sip3funcs.h"

Include dependency graph for sip3_dialog.c:

Go to the source code of this file.

Functions

void __sip_ack (struct sip_dialog *dialog, int seqno, int resp, int sipmethod, int reset)
 For a reliable transmission, we need to get an reply to stop retransmission. Acknowledges receipt of a packet and stops retransmission.
static int __sip_autodestruct (void *data)
 Kill a SIP dialog (called by scheduler).
void __sip_destroy (struct sip_dialog *dialog, int lockowner, int lockdialoglist)
 Execute destruction of SIP dialog structure, release memory.
GNURK void __sip_pretend_ack (struct sip_dialog *dialog)
 Pretend to ack all packets - nothing to do with SIP_ACK (the method) maybe the lock on p is not strictly necessary but there might be a race.
int __sip_semi_ack (struct sip_dialog *dialog, int seqno, int resp, int sipmethod)
 Acks receipt of packet, keep it around (used for provisional responses).
 AST_MUTEX_DEFINE_STATIC (dialoglock)
 Protect the SIP dialog list (of sip_dialog's).
 AST_THREADSTORAGE_CUSTOM (ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup)
 A per-thread temporary pvt structure.
GNURK void build_via (struct sip_dialog *dialog, int forcenewbranch)
 Build a Via header for a request.
static int dialog_activate_media (struct sip_dialog *dialog, struct sip_network *sipnet)
 Activate media streams - Audio, Video and T.38 UDPTL if needed.
void dialog_lock (struct sip_dialog *dialog, int state)
 Helper function to lock and unlock, hiding the underlying locking mechanism.
void dialoglist_lock (void)
 Lock list of active SIP dialogs.
void dialoglist_unlock (void)
 Unlock list of active SIP dialogs.
const char * dialogstate2str (const enum dialogstate state)
 Convert SIP dialog states to string.
void dialogstatechange (struct sip_dialog *dialog, enum dialogstate newstate)
 Change dialog state for a SIP dialog and output to debug.
GNURK void find_via_branch (struct sip_request *req, char *viabuf, size_t vialen)
 Find via branch parameter.
const char * hangup_cause2sip (int cause)
 Convert Asterisk hangup causes to SIP codes.
int hangup_sip2cause (int cause)
 Convert SIP hangup causes to Asterisk hangup causes.
GNURK void initialize_initreq (struct sip_dialog *dialog, struct sip_request *req)
 Initialize the initital request packet in the pvt structure. This packet is used for creating replies and future requests in a dialog.
GNURK void make_our_tag (char *tagbuf, size_t len)
 Make our SIP dialog tag.
sip_dialogmatch_or_create_dialog (struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
static char * ourdialogbranch (struct sip_dialog *dialog, int forcenewbranch)
 Make branch tag for via header if it does not exist yet.
void set_initreq (struct sip_dialog *dialog, struct sip_request *req)
 Set packet to initreq status. Set flag to avoid de-allocation until dialog is destroyed.
sip_dialogsip_alloc (ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method)
 Allocate SIP_PVT structure and set defaults.
GNURK void sip_cancel_destroy (struct sip_dialog *p)
 Cancel destruction of SIP dialog.
void sip_destroy (struct sip_dialog *dialog)
 Destroy SIP call structure.
GNURK void sip_scheddestroy (struct sip_dialog *p, int ms)
 Schedule destruction of SIP dialog.
static void temp_pvt_cleanup (void *data)
 Cleanup temporary PVT.
static int temp_pvt_init (void *data)
 Initialize temporary PVT.
int transmit_final_response (struct sip_dialog *dialog, const char *msg, struct sip_request *req, enum xmittype reliable)
 Transmit final response to a request and close dialog Set dialog state to TERMINATED to avoid problems At some point, after debugging, we can remove the reliable flag. Only responses to INVITEs are sent reliably.
static int transmit_response_using_temp (ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, struct sip_request *req, const char *msg)
 Transmit response, no retransmits, using a temporary pvt structure.


Function Documentation

void __sip_ack struct sip_dialog dialog,
int  seqno,
int  resp,
int  sipmethod,
int  reset
 

For a reliable transmission, we need to get an reply to stop retransmission. Acknowledges receipt of a packet and stops retransmission.

Note:
Assume that the dialog is locked.

Definition at line 261 of file sip3_dialog.c.

References ast_clear_flag, ast_log(), ast_sched_del(), ast_test_flag, sip_request::dialog, dialog_lock(), FALSE, LOG_DEBUG, sip_request::method, sip_request::next, option_debug, sip_dialog::packets, parse_request(), sip_dialog::pendinginvite, sip_request::retransid, sip_request::seqno, SIP_PKT_CONNECTED, SIP_PKT_INITREQ, SIP_PKT_PARSED, SIP_PKT_RESPONSE, sipdebug, siprequest_free(), TRUE, and UNLINK.

00262 {
00263    struct sip_request *cur, *prev = NULL;
00264    int res = FALSE;
00265 
00266    if (option_debug) {
00267       if (!resp)
00268          ast_log(LOG_DEBUG, "Trying to confirm pending invite %d Call ID %s\n", dialog->pendinginvite, dialog->callid);
00269       else
00270          ast_log(LOG_DEBUG, "Trying to confirm pending response on Call ID %s\n", dialog->callid);
00271    }
00272 
00273    dialog_lock(dialog, TRUE);
00274 
00275    /* Find proper transaction */
00276    for (cur = dialog->packets; cur; prev = cur, cur = cur->next) {
00277       if (option_debug > 2)
00278          ast_log(LOG_DEBUG, "--Checking packet with seqno %d against response with seqno %d\n", cur->seqno, seqno);
00279       /* Match on seqno AND req/resp AND method? */
00280       if ((cur->seqno == seqno) && ((ast_test_flag(cur, SIP_PKT_RESPONSE)) == resp) &&
00281          ((ast_test_flag(cur, SIP_PKT_RESPONSE)) || (cur->method == sipmethod))) {
00282          if (!resp && (seqno == dialog->pendinginvite)) {
00283             if (sipdebug && option_debug && !reset)
00284                ast_log(LOG_DEBUG, "Got reply to pending invite %d - Call Id %s\n", dialog->pendinginvite, dialog->callid);
00285             dialog->pendinginvite = 0;
00286          } else {
00287             if (sipdebug && option_debug && !reset)
00288                ast_log(LOG_DEBUG, "Got ACK on INVITE response Cseq %d Call Id %s\n", cur->seqno, dialog->callid);
00289          }
00290          /* this is our baby */
00291          res = TRUE;
00292          UNLINK(cur, dialog->packets, prev);
00293          if (cur->retransid > -1) {
00294             if (sipdebug && option_debug > 3 && !reset)
00295                ast_log(LOG_DEBUG, "Cancelling retransmit of packet (reply received) Retransid #%d\n", cur->retransid);
00296             ast_sched_del(sched, cur->retransid);
00297             cur->retransid = -1;
00298          }
00299          if (!reset) {
00300             if (!ast_test_flag(cur, SIP_PKT_INITREQ)) 
00301                siprequest_free(cur);   /* We might want to keep this somewhere else */
00302             else {
00303                if (sipdebug && option_debug > 3 && !reset)
00304                   ast_log(LOG_DEBUG, "This is the initial request, keeping it in memory - Cseq %d\n", cur->seqno);
00305                ast_clear_flag(cur, SIP_PKT_CONNECTED);
00306                if (!ast_test_flag(cur, SIP_PKT_PARSED))
00307                   parse_request(cur);  /* Parse initreq now, after we have answer */
00308             }
00309          }
00310          break;
00311       }
00312    }
00313    dialog_lock(dialog, FALSE);
00314    if (option_debug && sipdebug)
00315       ast_log(LOG_DEBUG, "Stopping retransmission on '%s' of %s %d: Match %s\n", dialog->callid, resp ? "Response" : "Request", seqno, res ? "Found" : "Not Found");
00316 }

static int __sip_autodestruct void *  data  )  [static]
 

Kill a SIP dialog (called by scheduler).

Definition at line 496 of file sip3_dialog.c.

References append_history, AST_EXTENSION_DEACTIVATED, ast_log(), ast_queue_hangup(), sip_dialog::autokillid, DEFAULT_TRANS_TIMEOUT, device_unref(), LOG_DEBUG, LOG_WARNING, sip_dialog::method, MWI_NOTIFICATION, NONE, option_debug, sip_dialog::owner, sip_dialog::refer, sip_dialog::relatedpeer, SIP_BYE, sip_destroy(), sip_method2txt(), sip_scheddestroy(), sip_dialog::subscribed, transmit_request_with_auth(), transmit_state_notify(), TRUE, and XMIT_RELIABLE.

00497 {
00498    struct sip_dialog *dialog = data;
00499 
00500    /* If this is a subscription, tell the phone that we got a timeout */
00501    if (dialog->subscribed) {
00502       transmit_state_notify(dialog, AST_EXTENSION_DEACTIVATED, 1, TRUE);   /* Send last notification */
00503       dialog->subscribed = NONE;
00504       append_history(dialog, "Subscribestatus", "timeout");
00505       if (option_debug > 2)
00506          ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP subsription %s\n", dialog->callid ? dialog->callid : "<unknown>");
00507       return 10000;  /* Reschedule this destruction so that we know that it's gone */
00508    }
00509 
00510    if (dialog->subscribed == MWI_NOTIFICATION && dialog->relatedpeer)
00511       device_unref(dialog->relatedpeer);
00512 
00513    /* Reset schedule ID */
00514    dialog->autokillid = -1;
00515 
00516    append_history(dialog, "AutoDestroy", "%s", dialog->callid);
00517    if (dialog->owner) {
00518       ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s)\n", dialog->callid, sip_method2txt(dialog->method));
00519       ast_queue_hangup(dialog->owner);
00520    } else if (dialog->refer) {
00521       if (option_debug > 2)
00522          ast_log(LOG_DEBUG, "Finally hanging up channel after transfer: %s\n", dialog->callid);
00523       transmit_request_with_auth(dialog, SIP_BYE, 0, XMIT_RELIABLE, 1);
00524       append_history(dialog, "ReferBYE", "Sending BYE on transferer call leg %s", dialog->callid);
00525       sip_scheddestroy(dialog, DEFAULT_TRANS_TIMEOUT);
00526    } else  {
00527       append_history(dialog, "AutoDestroy", "%s", dialog->callid);
00528       if (option_debug)
00529          ast_log(LOG_DEBUG, "Auto destroying SIP dialog '%s'\n", dialog->callid);
00530       sip_destroy(dialog);
00531    }
00532    return 0;
00533 }

void __sip_destroy struct sip_dialog dialog,
int  lockowner,
int  lockdialoglist
 

Execute destruction of SIP dialog structure, release memory.

Definition at line 366 of file sip3_dialog.c.

References ast_channel_lock, ast_channel_unlock, ast_extension_state_del(), AST_LIST_REMOVE_HEAD, ast_log(), ast_rtp_destroy(), ast_sched_del(), ast_test_flag, ast_udptl_destroy(), ast_verbose(), ASTOBJ_UNREF, DEC_CALL_LIMIT, DEC_CALL_RINGING, sip_request::dialog, dialoglist, dialoglist_lock(), sip_globals::dumphistory, sip_dialog::flags, free, free_old_route(), global, LOG_DEBUG, sip_dialog::next, option_debug, sip_debug_test_pvt(), sip_dump_history(), SIP_INC_COUNT, sip_method2txt(), SIP_PAGE2_INC_RINGING, sip_registry_destroy(), UNLINK, and update_call_counter().

00367 {
00368    struct sip_dialog *cur, *prev = NULL;
00369    struct sip_request *cp;
00370 
00371    if (ast_test_flag(&dialog->flags[0], SIP_INC_COUNT))        /* This dialog has incremented call count */
00372       update_call_counter(dialog, DEC_CALL_LIMIT);          /* Since it was forgotten, decrement call count */
00373 
00374    if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_INC_RINGING))         /* This dialog has incremented ring count */
00375       update_call_counter(dialog, DEC_CALL_RINGING);           /* Since it was forgotten, decrement ring count */
00376 
00377    if (sip_debug_test_pvt(dialog) || option_debug > 2)
00378       ast_verbose("Really destroying SIP dialog '%s' Method: %s\n", dialog->callid, sip_method2txt(dialog->method));
00379 
00380 
00381    /* Remove link from peer to subscription of MWI */
00382    if (dialog->relatedpeer && dialog->relatedpeer->mailbox.mwipvt)
00383       dialog->relatedpeer->mailbox.mwipvt = NULL;
00384 
00385    if (global.dumphistory)
00386       sip_dump_history(dialog);
00387 
00388 
00389    if (dialog->stateid > -1)
00390       ast_extension_state_del(dialog->stateid, NULL);
00391    if (dialog->initid > -1)
00392       ast_sched_del(sched, dialog->initid);
00393    if (dialog->autokillid > -1)
00394       ast_sched_del(sched, dialog->autokillid);
00395 
00396    if (dialog->inviteoptions)
00397       free(dialog->inviteoptions);
00398 
00399    if (dialog->rtp)
00400       ast_rtp_destroy(dialog->rtp);
00401    if (dialog->vrtp)
00402       ast_rtp_destroy(dialog->vrtp);
00403    if (dialog->udptl)
00404       ast_udptl_destroy(dialog->udptl);
00405    if (dialog->refer)
00406       free(dialog->refer);
00407    if (dialog->route) {
00408       free_old_route(dialog->route);
00409       dialog->route = NULL;
00410    }
00411    if (dialog->registry) {
00412       if (dialog->registry->call == dialog)
00413          dialog->registry->call = NULL;
00414       ASTOBJ_UNREF(dialog->registry, sip_registry_destroy);
00415    }
00416 
00417    /* Unlink us from the owner if we have one */
00418    if (dialog->owner) {
00419       if (lockowner)
00420          ast_channel_lock(dialog->owner);
00421       if (option_debug)
00422          ast_log(LOG_DEBUG, "Detaching from %s\n", dialog->owner->name);
00423       dialog->owner->tech_pvt = NULL;
00424       if (lockowner)
00425          ast_channel_unlock(dialog->owner);
00426    }
00427    /* Clear history */
00428    if (dialog->history) {
00429       struct sip_history *hist;
00430       while( (hist = AST_LIST_REMOVE_HEAD(dialog->history, list)) )
00431          free(hist);
00432       free(dialog->history);
00433       dialog->history = NULL;
00434    }
00435 
00436 
00437    /* Unlink us from the dialog list */
00438    if (lockdialoglist)
00439       dialoglist_lock();
00440    for (prev = NULL, cur = dialoglist; cur; prev = cur, cur = cur->next) {
00441       if (cur == dialog) {
00442          UNLINK(cur, dialoglist, prev);
00443          break;
00444       }
00445    }
00446    if (lockdialoglist)
00447       dialoglist_unlock();
00448 
00449    if (!cur) {
00450       ast_log(LOG_WARNING, "Trying to destroy \"%s\", not found in dialog list?!?! \n", dialog->callid);
00451       return;
00452    } 
00453 
00454    /* remove all current packets in this dialog */
00455    while((cp = dialog->packets)) {
00456       /* If one of the records in the packet list is the initreq, then release it */
00457       if (cp == dialog->initreq)
00458          dialog->initreq = NULL;
00459 
00460       dialog->packets = dialog->packets->next;
00461       if (cp->retransid > -1)
00462          ast_sched_del(sched, cp->retransid);
00463       free(cp);
00464    }
00465 
00466    if (dialog->initreq)
00467       siprequest_free(dialog->initreq);
00468 
00469    if (dialog->chanvars) {
00470       ast_variables_destroy(dialog->chanvars);
00471       dialog->chanvars = NULL;
00472    }
00473    ast_mutex_destroy(&dialog->lock);
00474 
00475    ast_string_field_free_pools(dialog);
00476 
00477    /* Finally, release the dialog */
00478    free(dialog);
00479 
00480    sipcounters.dialog_objects--;
00481    if (option_debug > 3)
00482       ast_log(LOG_DEBUG, "--DIALOGS-- Counter %d\n", sipcounters.dialog_objects);
00483 }

GNURK void __sip_pretend_ack struct sip_dialog dialog  ) 
 

Pretend to ack all packets - nothing to do with SIP_ACK (the method) maybe the lock on p is not strictly necessary but there might be a race.

Definition at line 320 of file sip3_dialog.c.

References __sip_ack(), ast_log(), ast_test_flag, sip_request::data, sip_request::dialog, FALSE, find_sip_method(), LOG_WARNING, sip_request::method, sip_dialog::packets, sip_request::seqno, sip_method2txt(), and SIP_PKT_RESPONSE.

00321 {
00322    struct sip_request *cur = NULL;
00323 
00324    while (dialog->packets) {
00325       int method;
00326       if (cur == dialog->packets) {
00327          ast_log(LOG_WARNING, "Have a packet that doesn't want to give up! %s\n", sip_method2txt(cur->method));
00328          return;
00329       }
00330       cur = dialog->packets;
00331       method = (cur->method) ? cur->method : find_sip_method(cur->data);
00332       __sip_ack(dialog, cur->seqno, ast_test_flag(cur, SIP_PKT_RESPONSE), method, FALSE);
00333    }
00334 }

int __sip_semi_ack struct sip_dialog dialog,
int  seqno,
int  resp,
int  sipmethod
 

Acks receipt of packet, keep it around (used for provisional responses).

Note:
Assume that the dialog is locked.

Definition at line 339 of file sip3_dialog.c.

References ast_log(), ast_sched_del(), ast_test_flag, sip_request::data, sip_request::dialog, LOG_DEBUG, method_match(), sip_request::next, option_debug, sip_dialog::packets, sip_request::retransid, sip_request::seqno, sip_method2txt(), SIP_PKT_RESPONSE, and sipdebug.

00340 {
00341    struct sip_request *cur;
00342    int res = -1;
00343 
00344    for (cur = dialog->packets; cur; cur = cur->next) {
00345       if (option_debug > 2)
00346          ast_log(LOG_DEBUG, "--Checking packet with seqno %d against response with seqno %d\n", cur->seqno, seqno);
00347       if (cur->seqno == seqno && ast_test_flag(cur, SIP_PKT_RESPONSE) == resp &&
00348          (ast_test_flag(cur, SIP_PKT_RESPONSE) || method_match(sipmethod, cur->data))) {
00349          /* this is our baby */
00350          if (cur->retransid > -1) {
00351             if (option_debug > 3 && sipdebug)
00352                ast_log(LOG_DEBUG, "Cancelling retransmission #%d - %s (got response)\n", cur->retransid, sip_method2txt(sipmethod));
00353             ast_sched_del(sched, cur->retransid);
00354          }
00355          cur->retransid = -1;
00356          res = 0;
00357          break;
00358       }
00359    }
00360    if (option_debug)
00361       ast_log(LOG_DEBUG, "(Provisional) Stopping retransmission (but retaining packet) on '%s' %s %d: %s\n", dialog->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found");
00362    return res;
00363 }

AST_MUTEX_DEFINE_STATIC dialoglock   ) 
 

Protect the SIP dialog list (of sip_dialog's).

AST_THREADSTORAGE_CUSTOM ts_temp_pvt  ,
temp_pvt_init  ,
temp_pvt_cleanup 
 

A per-thread temporary pvt structure.

GNURK void build_via struct sip_dialog dialog,
int  forcenewbranch
 

Build a Via header for a request.

Definition at line 1236 of file sip3_dialog.c.

References ast_inet_ntoa(), ast_string_field_build, ast_test_flag, sip_dialog::flags, ourdialogbranch(), sip_dialog::ourip, SIP_NAT, SIP_NAT_RFC3581, sipnet, and sipnet_ourport().

01237 {
01238    /* Work around buggy UNIDEN UIP200 firmware */
01239    const char *rport = ast_test_flag(&dialog->flags[0], SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : "";
01240 
01241    /* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
01242    ast_string_field_build(dialog, via, "SIP/2.0/UDP %s:%d;branch=%s%s",
01243          ast_inet_ntoa(dialog->ourip), sipnet_ourport(&sipnet), 
01244          ourdialogbranch(dialog, forcenewbranch), rport);
01245 }

static int dialog_activate_media struct sip_dialog dialog,
struct sip_network sipnet
[static]
 

Activate media streams - Audio, Video and T.38 UDPTL if needed.

Definition at line 738 of file sip3_dialog.c.

References ast_log(), ast_rtp_new_with_bindaddr(), ast_rtp_set_rtpholdtimeout(), ast_rtp_set_rtpkeepalive(), ast_rtp_set_rtptimeout(), ast_rtp_setdtmf(), ast_rtp_setdtmfcompensate(), ast_rtp_settos(), ast_test_flag, ast_udptl_get_error_correction_scheme(), ast_udptl_new_with_bindaddr(), ast_udptl_settos(), sip_network::bindaddr, t38properties::capability, sip_globals::default_maxcallbitrate, FALSE, sip_dialog::flags, global, io, t38properties::jointcapability, LOG_DEBUG, LOG_WARNING, sip_dialog::maxcallbitrate, option_debug, sip_dialog::rtp, rtptimers::rtpholdtimeout, rtptimers::rtpkeepalive, rtptimers::rtptimeout, sip_globals::rtptimer, SIP_DTMF, SIP_DTMF_INFO, SIP_PAGE2_RFC2833_COMPENSATE, SIP_PAGE2_T38SUPPORT, SIP_PAGE2_VIDEOSUPPORT, sipnet, sip_dialog::t38, sip_globals::t38_capability, T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF, T38FAX_UDP_EC_FEC, T38FAX_UDP_EC_NONE, T38FAX_UDP_EC_REDUNDANCY, sip_globals::tos_audio, sip_globals::tos_video, TRUE, sip_dialog::udptl, UDPTL_ERROR_CORRECTION_FEC, UDPTL_ERROR_CORRECTION_NONE, UDPTL_ERROR_CORRECTION_REDUNDANCY, and sip_dialog::vrtp.

Referenced by sip_alloc().

00739 {
00740    /* Audio channel is always activated */
00741    dialog->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, sipnet->bindaddr.sin_addr);
00742 
00743    /* If the global videosupport flag is on, we always create a RTP interface for video */
00744    if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT)) {
00745       if (option_debug > 3)
00746          ast_log(LOG_DEBUG, "Creating video interface for %s\n", dialog->callid);
00747       dialog->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, sipnet->bindaddr.sin_addr);
00748    }
00749 
00750    /* T.38 support UDPTL stream */
00751    if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) {
00752       if (option_debug > 3)
00753          ast_log(LOG_DEBUG, "Creating UDPTL interface for %s\n", dialog->callid);
00754       dialog->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, sipnet->bindaddr.sin_addr);
00755       if (!dialog->udptl)
00756          ast_log(LOG_WARNING, "Unable to create T.38 UDPTL interface for session: %s\n", dialog->callid);
00757    }
00758 
00759    /* Do we have channels? */
00760    if (!dialog->rtp || (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !dialog->vrtp)) {
00761       ast_log(LOG_WARNING, "Unable to create RTP audio %s session: %s\n",
00762       ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "and video" : "", strerror(errno));
00763       return FALSE;
00764    }
00765 
00766    /* Fine tune audio RTP settings */
00767    ast_rtp_setdtmf(dialog->rtp, ast_test_flag(&dialog->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
00768    ast_rtp_setdtmfcompensate(dialog->rtp, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
00769    ast_rtp_settos(dialog->rtp, global.tos_audio);
00770    ast_rtp_set_rtptimeout(dialog->rtp, global.rtptimer.rtptimeout);
00771    ast_rtp_set_rtpholdtimeout(dialog->rtp, global.rtptimer.rtpholdtimeout);
00772    ast_rtp_set_rtpkeepalive(dialog->rtp, global.rtptimer.rtpkeepalive);
00773 
00774    /* If we have video, fine tune RTP settings */
00775    if (dialog->vrtp) {
00776       ast_rtp_settos(dialog->vrtp, global.tos_video);
00777       ast_rtp_setdtmf(dialog->vrtp, 0);
00778       ast_rtp_setdtmfcompensate(dialog->vrtp, 0);
00779       ast_rtp_set_rtptimeout(dialog->vrtp, global.rtptimer.rtptimeout);
00780       ast_rtp_set_rtpholdtimeout(dialog->vrtp, global.rtptimer.rtpholdtimeout);
00781       ast_rtp_set_rtpkeepalive(dialog->vrtp, global.rtptimer.rtpkeepalive);
00782    }
00783 
00784    /* Finally, T.38 settings */
00785    if (dialog->udptl) {
00786       ast_udptl_settos(dialog->udptl, global.tos_audio);
00787       dialog->t38.capability = global.t38_capability;
00788       if (ast_udptl_get_error_correction_scheme(dialog->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY)
00789          dialog->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
00790       else if (ast_udptl_get_error_correction_scheme(dialog->udptl) == UDPTL_ERROR_CORRECTION_FEC)
00791          dialog->t38.capability |= T38FAX_UDP_EC_FEC;
00792       else if (ast_udptl_get_error_correction_scheme(dialog->udptl) == UDPTL_ERROR_CORRECTION_NONE)
00793          dialog->t38.capability |= T38FAX_UDP_EC_NONE;
00794       dialog->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
00795       dialog->t38.jointcapability = dialog->t38.capability;
00796    }
00797 
00798    dialog->maxcallbitrate = global.default_maxcallbitrate;
00799    return TRUE;
00800 }

void dialog_lock struct sip_dialog dialog,
int  state
 

Helper function to lock and unlock, hiding the underlying locking mechanism.

Parameters:
state TRUE for lock, FALSE for unlock

Definition at line 146 of file sip3_dialog.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), sip_dialog::lock, LOG_DEBUG, LOG_ERROR, option_debug, and sipdebug.

Referenced by __sip_ack(), auto_congest(), check_rtp_timeout(), get_sip_dialog_byid_locked(), handle_invite_replaces(), handle_request_invite(), handle_request_subscribe(), handle_response_answer(), local_attended_transfer(), process_sip_queue(), retrans_pkt(), sip_answer(), sip_dtmfmode(), sip_fixup(), sip_get_rtp_peer(), sip_get_udptl_peer(), sip_handle_t38_reinvite(), sip_hangup(), sip_indicate(), sip_new(), sip_read(), sip_senddigit_begin(), sip_senddigit_end(), sip_set_rtp_peer(), sip_transfer(), sip_write(), and write_media_frame().

00147 {
00148    if (!dialog) {
00149       ast_log(LOG_ERROR, "-DIALOGLOCK- Trying to %s non-existing dialog. Giving up.\n", state ? "lock" : "unlock");
00150       return;
00151    }
00152    if (sipdebug && option_debug > 4)
00153       ast_log(LOG_DEBUG, "-DIALOGLOCK- %s dialog %s\n", state ? "  locking" : "unlocking", dialog->callid ? dialog->callid : "<no callid>");
00154 
00155    if (state)
00156       ast_mutex_lock(&dialog->lock);
00157    else
00158       ast_mutex_unlock(&dialog->lock);
00159 }

void dialoglist_lock void   ) 
 

Lock list of active SIP dialogs.

Definition at line 122 of file sip3_dialog.c.

References ast_log(), ast_mutex_lock(), ast_mutex_trylock(), LOG_DEBUG, option_debug, and sipdebug.

00123 {
00124    int counter = 0;
00125    while (ast_mutex_trylock(&dialoglock) && counter < 100) {
00126       if (option_debug > 4)
00127          ast_log(LOG_DEBUG, "---Trying to lock dialoglist -- %d \n", ++counter);
00128    } 
00129    if (counter == 100)
00130       ast_mutex_lock(&dialoglock);
00131    if (sipdebug && option_debug > 4)
00132       ast_log(LOG_DEBUG, "=== SIP dialog list: LOCKED\n");
00133 }

void dialoglist_unlock void   ) 
 

Unlock list of active SIP dialogs.

Definition at line 136 of file sip3_dialog.c.

References ast_log(), ast_mutex_unlock(), LOG_DEBUG, option_debug, and sipdebug.

00137 {
00138    ast_mutex_unlock(&dialoglock);
00139    if (sipdebug && option_debug > 4)
00140       ast_log(LOG_DEBUG, "=== SIP dialog list: UNLOCKED\n");
00141 }

const char* dialogstate2str const enum dialogstate  state  ) 
 

Convert SIP dialog states to string.

Definition at line 162 of file sip3_dialog.c.

References DIALOG_STATE_CONFIRMED, DIALOG_STATE_CONFIRMED_HOLD, DIALOG_STATE_EARLY, DIALOG_STATE_PROCEEDING, DIALOG_STATE_TERMINATED, DIALOG_STATE_TERMINATED_AUTH, and DIALOG_STATE_TRYING.

Referenced by dialogstatechange(), sip_hangup(), and sip_show_channel().

00163 {
00164    const char *reply = "<unknown>";
00165    switch (state) {
00166    case DIALOG_STATE_TRYING:
00167       reply = "Trying";
00168       break;
00169    case DIALOG_STATE_PROCEEDING:
00170       reply = "Proceeding";
00171       break;
00172    case DIALOG_STATE_EARLY:
00173       reply = "Early";
00174       break;
00175    case DIALOG_STATE_CONFIRMED:
00176       reply = "Confirmed";
00177       break;
00178    case DIALOG_STATE_CONFIRMED_HOLD:
00179       reply = "Confirmed, on hold";
00180       break;
00181    case DIALOG_STATE_TERMINATED:
00182       reply = "Terminated";
00183       break;
00184    case DIALOG_STATE_TERMINATED_AUTH:
00185       reply = "Terminated, auth";
00186       break;
00187    }
00188    return reply;
00189 }

void dialogstatechange struct sip_dialog dialog,
enum dialogstate  newstate
 

Change dialog state for a SIP dialog and output to debug.

Definition at line 192 of file sip3_dialog.c.

References append_history, ast_log(), dialogstate2str(), global, sip_dialog::icseq, LOG_DEBUG, sip_dialog::ocseq, option_debug, sip_globals::recordhistory, sipdebug, and sip_dialog::state.

Referenced by handle_request(), handle_request_info(), handle_request_invite(), handle_request_subscribe(), handle_response_invite(), handle_response_notify(), handle_response_peerpoke(), sip_alloc(), sip_answer(), sip_hangup(), sip_indicate(), and transmit_final_response().

00193 {
00194    if (dialog->state == newstate) {
00195       if (option_debug > 3)
00196          ast_log(LOG_DEBUG, "Asked to change state to dialog that already has requested state: %s State %s\n", dialog->callid, dialogstate2str(newstate));
00197    } else {
00198       dialog->state = newstate;
00199       if (sipdebug && option_debug > 1)
00200          ast_log(LOG_DEBUG, "-- Dialog %s changed state to %s\n", dialog->callid, dialogstate2str(newstate));
00201       if (global.recordhistory)
00202          append_history(dialog, "DialogState", "New state: %s O-Cseq %d I-Cseq %d", dialogstate2str(newstate), dialog->ocseq, dialog->icseq);
00203    }
00204    /* When state is terminated, keep it for 32 secs to allow for retransmits 
00205     */
00206 }

GNURK void find_via_branch struct sip_request req,
char *  viabuf,
size_t  vialen
 

Find via branch parameter.

Definition at line 1196 of file sip3_dialog.c.

References ast_log(), ast_strdupa, ast_strlen_zero(), ast_test_flag, LOG_DEBUG, option_debug, SIP_PKT_DEBUG, strcasestr(), and sip_request::via.

Referenced by match_or_create_dialog().

01197 {
01198    char *dupvia;
01199    char *viabranch;
01200    char *sep;
01201 
01202    if (ast_strlen_zero(req->via))
01203       return;
01204    dupvia = ast_strdupa(req->via);
01205    if (!(viabranch = strcasestr(dupvia, ";branch=")))
01206       return;
01207    viabranch += 8;
01208    if ((sep = strchr(viabranch, ';')))
01209       *sep = '\0';
01210    if (ast_test_flag(req, SIP_PKT_DEBUG) && option_debug > 3)
01211       ast_log(LOG_DEBUG, "* Found via branch %s\n", viabranch);
01212    strncpy(viabuf, viabranch, vialen);
01213 }

const char* hangup_cause2sip int  cause  ) 
 

Convert Asterisk hangup causes to SIP codes.

 Possible values from causes.h
        AST_CAUSE_NOTDEFINED    AST_CAUSE_NORMAL        AST_CAUSE_BUSY
        AST_CAUSE_FAILURE       AST_CAUSE_CONGESTION    AST_CAUSE_UNALLOCATED

	In addition to these, a lot of PRI codes is defined in causes.h 
	...should we take care of them too ?
	
	Quote RFC 3398

   ISUP Cause value                        SIP response
   ----------------                        ------------
   1  unallocated number                   404 Not Found
   2  no route to network                  404 Not found
   3  no route to destination              404 Not found
   16 normal call clearing                 --- (*)
   17 user busy                            486 Busy here
   18 no user responding                   408 Request Timeout
   19 no answer from the user              480 Temporarily unavailable
   20 subscriber absent                    480 Temporarily unavailable
   21 call rejected                        403 Forbidden (+)
   22 number changed (w/o diagnostic)      410 Gone
   22 number changed (w/ diagnostic)       301 Moved Permanently
   23 redirection to new destination       410 Gone
   26 non-selected user clearing           404 Not Found (=)
   27 destination out of order             502 Bad Gateway
   28 address incomplete                   484 Address incomplete
   29 facility rejected                    501 Not implemented
   31 normal unspecified                   480 Temporarily unavailable

Definition at line 681 of file sip3_dialog.c.

References AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, AST_CAUSE_CALL_REJECTED, AST_CAUSE_CHAN_NOT_IMPLEMENTED, AST_CAUSE_CONGESTION, AST_CAUSE_DESTINATION_OUT_OF_ORDER, AST_CAUSE_FACILITY_REJECTED, AST_CAUSE_FAILURE, AST_CAUSE_INVALID_NUMBER_FORMAT, AST_CAUSE_NO_ANSWER, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_NO_ROUTE_TRANSIT_NET, AST_CAUSE_NO_USER_RESPONSE, AST_CAUSE_NORMAL_UNSPECIFIED, AST_CAUSE_NOTDEFINED, AST_CAUSE_NUMBER_CHANGED, AST_CAUSE_SWITCH_CONGESTION, AST_CAUSE_UNALLOCATED, AST_CAUSE_USER_BUSY, ast_log(), LOG_DEBUG, and option_debug.

00682 {
00683    switch (cause) {
00684       case AST_CAUSE_UNALLOCATED:      /* 1 */
00685       case AST_CAUSE_NO_ROUTE_DESTINATION:   /* 3 IAX2: Can't find extension in context */
00686       case AST_CAUSE_NO_ROUTE_TRANSIT_NET:   /* 2 */
00687          return "404 Not Found";
00688       case AST_CAUSE_CONGESTION:    /* 34 */
00689       case AST_CAUSE_SWITCH_CONGESTION:   /* 42 */
00690          return "503 Service Unavailable";
00691       case AST_CAUSE_NO_USER_RESPONSE: /* 18 */
00692          return "408 Request Timeout";
00693       case AST_CAUSE_NO_ANSWER:     /* 19 */
00694          return "480 Temporarily unavailable";
00695       case AST_CAUSE_CALL_REJECTED:    /* 21 */
00696          return "403 Forbidden";
00697       case AST_CAUSE_NUMBER_CHANGED:      /* 22 */
00698          return "410 Gone";
00699       case AST_CAUSE_NORMAL_UNSPECIFIED:  /* 31 */
00700          return "480 Temporarily unavailable";
00701       case AST_CAUSE_INVALID_NUMBER_FORMAT:
00702          return "484 Address incomplete";
00703       case AST_CAUSE_USER_BUSY:
00704          return "486 Busy here";
00705       case AST_CAUSE_FAILURE:
00706          return "500 Server internal failure";
00707       case AST_CAUSE_FACILITY_REJECTED:   /* 29 */
00708          return "501 Not Implemented";
00709       case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
00710          return "503 Service Unavailable";
00711       /* Used in chan_iax2 */
00712       case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
00713          return "502 Bad Gateway";
00714       case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL: /* Can't find codec to connect to host */
00715          return "488 Not Acceptable Here";
00716          
00717       case AST_CAUSE_NOTDEFINED:
00718       default:
00719          if (option_debug)
00720             ast_log(LOG_DEBUG, "AST hangup cause %d (no match found in SIP)\n", cause);
00721          return NULL;
00722    }
00723 
00724    /* Never reached */
00725    return 0;
00726 }

int hangup_sip2cause int  cause  ) 
 

Convert SIP hangup causes to Asterisk hangup causes.

Definition at line 567 of file sip3_dialog.c.

References AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, AST_CAUSE_BUSY, AST_CAUSE_CALL_REJECTED, AST_CAUSE_CONGESTION, AST_CAUSE_DESTINATION_OUT_OF_ORDER, AST_CAUSE_FACILITY_REJECTED, AST_CAUSE_FAILURE, AST_CAUSE_INTERWORKING, AST_CAUSE_INVALID_NUMBER_FORMAT, AST_CAUSE_NO_ANSWER, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_NO_USER_RESPONSE, AST_CAUSE_NORMAL, AST_CAUSE_NORMAL_TEMPORARY_FAILURE, AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, AST_CAUSE_UNALLOCATED, and AST_CAUSE_USER_BUSY.

00568 {
00569    /* Possible values taken from causes.h */
00570 
00571    switch(cause) {
00572       case 401:   /* Unauthorized */
00573          return AST_CAUSE_CALL_REJECTED;
00574       case 403:   /* Not found */
00575          return AST_CAUSE_CALL_REJECTED;
00576       case 404:   /* Not found */
00577          return AST_CAUSE_UNALLOCATED;
00578       case 405:   /* Method not allowed */
00579          return AST_CAUSE_INTERWORKING;
00580       case 407:   /* Proxy authentication required */
00581          return AST_CAUSE_CALL_REJECTED;
00582       case 408:   /* No reaction */
00583          return AST_CAUSE_NO_USER_RESPONSE;
00584       case 409:   /* Conflict */
00585          return AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
00586       case 410:   /* Gone */
00587          return AST_CAUSE_UNALLOCATED;
00588       case 411:   /* Length required */
00589          return AST_CAUSE_INTERWORKING;
00590       case 413:   /* Request entity too large */
00591          return AST_CAUSE_INTERWORKING;
00592       case 414:   /* Request URI too large */
00593          return AST_CAUSE_INTERWORKING;
00594       case 415:   /* Unsupported media type */
00595          return AST_CAUSE_INTERWORKING;
00596       case 420:   /* Bad extension */
00597          return AST_CAUSE_NO_ROUTE_DESTINATION;
00598       case 480:   /* No answer */
00599          return AST_CAUSE_NO_ANSWER;
00600       case 481:   /* No answer */
00601          return AST_CAUSE_INTERWORKING;
00602       case 482:   /* Loop detected */
00603          return AST_CAUSE_INTERWORKING;
00604       case 483:   /* Too many hops */
00605          return AST_CAUSE_NO_ANSWER;
00606       case 484:   /* Address incomplete */
00607          return AST_CAUSE_INVALID_NUMBER_FORMAT;
00608       case 485:   /* Ambigous */
00609          return AST_CAUSE_UNALLOCATED;
00610       case 486:   /* Busy everywhere */
00611          return AST_CAUSE_BUSY;
00612       case 487:   /* Request terminated */
00613          return AST_CAUSE_INTERWORKING;
00614       case 488:   /* No codecs approved */
00615          return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
00616       case 491:   /* Request pending */
00617          return AST_CAUSE_INTERWORKING;
00618       case 493:   /* Undecipherable */
00619          return AST_CAUSE_INTERWORKING;
00620       case 500:   /* Server internal failure */
00621          return AST_CAUSE_FAILURE;
00622       case 501:   /* Call rejected */
00623          return AST_CAUSE_FACILITY_REJECTED;
00624       case 502:   
00625          return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
00626       case 503:   /* Service unavailable */
00627          return AST_CAUSE_CONGESTION;
00628       case 504:   /* Gateway timeout */
00629          return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
00630       case 505:   /* SIP version not supported */
00631          return AST_CAUSE_INTERWORKING;
00632       case 600:   /* Busy everywhere */
00633          return AST_CAUSE_USER_BUSY;
00634       case 603:   /* Decline */
00635          return AST_CAUSE_CALL_REJECTED;
00636       case 604:   /* Does not exist anywhere */
00637          return AST_CAUSE_UNALLOCATED;
00638       case 606:   /* Not acceptable */
00639          return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
00640       default:
00641          return AST_CAUSE_NORMAL;
00642    }
00643    /* Never reached */
00644    return 0;
00645 }

GNURK void initialize_initreq struct sip_dialog dialog,
struct sip_request req
 

Initialize the initital request packet in the pvt structure. This packet is used for creating replies and future requests in a dialog.

Definition at line 239 of file sip3_dialog.c.

References ast_log(), ast_test_flag, ast_verbose(), sip_request::headers, sip_dialog::initreq, sip_request::lines, LOG_DEBUG, option_debug, set_initreq(), SIP_PKT_CONNECTED, SIP_PKT_DEBUG, and siprequest_free().

00240 {
00241    /* If we already have an initial req, free it if it's not waiting for an ACK */
00242    if (dialog->initreq) {
00243       if (option_debug > 2)
00244          ast_log(LOG_DEBUG, "Initializing already initialized SIP dialog %s (presumably reinvite)\n", dialog->callid);
00245       if (!ast_test_flag(dialog->initreq, SIP_PKT_CONNECTED))
00246          siprequest_free(dialog->initreq);
00247    }
00248    /* Use this as the basis */
00249    set_initreq(dialog, req);
00250    //parse_request(dialog->initreq);
00251    if (ast_test_flag(req, SIP_PKT_DEBUG))
00252       ast_verbose("Initreq: %d headers, %d lines\n", dialog->initreq->headers, dialog->initreq->lines);
00253 }

GNURK void make_our_tag char *  tagbuf,
size_t  len
 

Make our SIP dialog tag.

Definition at line 729 of file sip3_dialog.c.

References ast_random(), and sipdebug.

00730 {
00731    if (sipdebug)
00732       snprintf(tagbuf, len, "asterisk%08lx", ast_random());
00733    else
00734       snprintf(tagbuf, len, "%08lx", ast_random());
00735 }

struct sip_dialog* match_or_create_dialog struct sip_request req,
struct sockaddr_in *  sin,
const int  intended_method
 

Definition at line 1053 of file sip3_dialog.c.

References ast_log(), ast_set_flag, ast_strlen_zero(), sip_request::callid, sip_request::cseqheader, dialoglist, dialoglist_lock(), FALSE, find_via_branch(), sip_request::from, get_header(), gettag(), LOG_DEBUG, sip_dialog::next, option_debug, SIP_ACK, SIP_BYE, SIP_INFO, sip_methods, SIP_PKT_WITH_TOTAG, SIP_REGISTER, SIP_RESPONSE, sip_dialog::tag, cfsip_methods::text, and sip_request::to.

Referenced by process_sip_queue().

01054 {
01055    struct sip_dialog *cur = NULL;
01056    char *tag = "";   /* note, tag is never NULL */
01057    char totag[128];
01058    char fromtag[128];
01059    char branch[128];
01060 
01061    if (ast_strlen_zero(req->callid))
01062       req->callid = get_header(req, "Call-ID");
01063    if (ast_strlen_zero(req->from))
01064       req->from = get_header(req, "From");
01065    if (ast_strlen_zero(req->to))
01066       req->to = get_header(req, "To");
01067    if (ast_strlen_zero(req->cseqheader))
01068       req->cseqheader = get_header(req, "Cseq");
01069 
01070    /* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
01071    /* get_header always returns non-NULL so we must use ast_strlen_zero() */
01072    if (ast_strlen_zero(req->callid) || ast_strlen_zero(req->to) ||
01073          ast_strlen_zero(req->from) || ast_strlen_zero(req->cseqheader))
01074       return NULL;   /* Invalid packet */
01075 
01076    /* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
01077       we need more to identify a branch - so we have to check branch, from
01078       and to tags to identify a call leg.
01079       */
01080    if (gettag(req->to, totag, sizeof(totag)))
01081       ast_set_flag(req, SIP_PKT_WITH_TOTAG); /* Used in handle_request/response */
01082    gettag(req->from, fromtag, sizeof(fromtag));
01083 
01084    tag = (req->method == SIP_RESPONSE) ? totag : fromtag;
01085 
01086    /* All messages must always have From: tag */
01087    if (ast_strlen_zero(fromtag)) {
01088       if (option_debug > 4 ) 
01089          ast_log(LOG_DEBUG, "%s request has no from tag, dropping callid: %s from: %s\n", sip_methods[req->method].text, req->callid, req->from );
01090       return NULL;
01091    }
01092    /* reject requests that must always have a To: tag */
01093    if (ast_strlen_zero(totag) && (req->method == SIP_ACK || req->method == SIP_BYE || req->method == SIP_INFO )) {
01094       if (option_debug > 4) 
01095          ast_log(LOG_DEBUG, "%s must have a to tag. dropping callid: %s from: %s\n", sip_methods[req->method].text, req->callid, req->from );
01096       return NULL;
01097    }
01098  
01099    dialoglist_lock();
01100 
01101    if (option_debug > 4 )
01102       ast_log(LOG_DEBUG, "= Looking for  Call ID: %s (Checking %s) --From tag %s --To-tag %s  \n", req->callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
01103 
01104    find_via_branch(req, branch, sizeof(branch));
01105    for (cur = dialoglist; cur; cur = cur->next) {
01106       /* we do not want packets with bad syntax to be connected to a PVT */
01107       int found = FALSE;
01108       if (req->method == SIP_REGISTER)
01109          found = (!strcmp(cur->callid, req->callid));
01110       else 
01111          found = (!strcmp(cur->callid, req->callid) && 
01112          (!tag || ast_strlen_zero(cur->theirtag) || !strcmp(cur->theirtag, tag))) ;
01113 
01114       if (option_debug > 4)
01115          ast_log(LOG_DEBUG, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", cur->callid, cur->theirtag, cur->tag);
01116 
01117       /* If we get a new request within an existing to-tag - check the to tag as well */
01118       if (found  && req->method != SIP_RESPONSE) { /* SIP Request */
01119          if (cur->tag[0] == '\0' && totag[0]) {
01120             /* We have no to tag, but they have. Wrong dialog */
01121             found = FALSE;
01122          } else if (totag[0]) {        /* Both have tags, compare them */
01123             if (strcmp(totag, cur->tag)) {
01124                found = FALSE;    /* This is not our dialog */
01125             }
01126          }
01127          if (!found && option_debug > 4)
01128             ast_log(LOG_DEBUG, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", cur->callid, totag, sip_method2txt(req->method));
01129       }
01130       
01131       /* We need to check the branch too, to make sure this is the proper reply */
01132       /* If it is an INVITE from us coming back with a new branch, we need to
01133          do some masquerading trickery with the audio.
01134          We might also get several INVITEs with different branches
01135          and have to treat them as several calls 
01136        */
01137       if (found) {
01138          if (!strcmp(cur->ourbranch, branch)) {
01139             /* This is our own request coming back to us strangely enough */
01140             /* Propably through DNS, but not a proxy */
01141             /* Bad dialplan design... ; -) */
01142             /* Any way we can handle this??? */
01143          }
01144          /* If we have a remote branch already, and get a new branch with the
01145             same call ID, then something is happening.
01146             For responses - we might have a forking proxy and get responses
01147             from several UAs on one request.
01148             For requests, we might be getting a statelessly forked call to us. 
01149          */
01150          if (!ast_strlen_zero(cur->remotebranch) && strcmp(cur->remotebranch, branch)) {
01151             /* XXX What do we do here ? */
01152             
01153          }
01154       }
01155 
01156 
01157       if (found) {
01158          /* Found the dialog */
01159          dialog_lock(cur, TRUE); /* Lock the dialog */
01160          dialoglist_unlock(); /* Unlock the list */
01161          return cur;
01162       }
01163    }
01164    dialoglist_unlock();
01165    if (sip_methods[intended_method].creates_dialog != CAN_CREATE_DIALOG) {
01166       if (intended_method != SIP_RESPONSE && intended_method != SIP_ACK)
01167          transmit_response_using_temp(req->callid, sin, TRUE, intended_method, req, "481 Call leg/transaction does not exist");
01168       else
01169          logdebug(2, "Got response or ACK to non-existing transaction. No action taken. Call-ID: %s\n", req->callid);
01170       return cur;
01171    }
01172    switch (intended_method) {
01173    case SIP_REFER:
01174       /* We do not support out-of-dialog REFERs yet */
01175       transmit_response_using_temp(req->callid, sin, TRUE, intended_method, req, "603 Declined (no dialog)");
01176       break;
01177    case SIP_NOTIFY:
01178       /* We do not support out-of-dialog NOTIFY either,
01179         like voicemail notification, so cancel that early */
01180       transmit_response_using_temp(req->callid, sin, TRUE, intended_method, req, "489 Bad event");
01181       break;
01182    default:
01183       /* ready to create a new dialog. */
01184       if ((cur = sip_alloc(req->callid, sin, TRUE, intended_method))) {
01185          /* This method creates dialog */
01186          /* Ok,   we've created a dialog, let's go and process it */
01187          dialog_lock(cur, TRUE);
01188       }
01189       break;
01190    }
01191 
01192    return cur;
01193 }

static char* ourdialogbranch struct sip_dialog dialog,
int  forcenewbranch
[static]
 

Make branch tag for via header if it does not exist yet.

Definition at line 1217 of file sip3_dialog.c.

References ast_random(), ast_string_field_set, and ast_strlen_zero().

Referenced by build_via().

01218 {
01219    char branch[20];
01220    int seed = 0;
01221 
01222    if (forcenewbranch || ast_strlen_zero(dialog->ourbranch)) {
01223       if (forcenewbranch)
01224          seed ^= ast_random();
01225       else
01226          seed = ast_random();
01227       snprintf(branch, sizeof(branch), "z9hG4bk%08x", seed);
01228       ast_string_field_set(dialog, ourbranch, branch);
01229    }
01230 
01231    return((char *) dialog->ourbranch);
01232    
01233 }

void set_initreq struct sip_dialog dialog,
struct sip_request req
 

Set packet to initreq status. Set flag to avoid de-allocation until dialog is destroyed.

Definition at line 229 of file sip3_dialog.c.

References ast_set_flag, sip_dialog::initreq, and SIP_PKT_INITREQ.

Referenced by handle_request_bye(), handle_request_invite(), handle_request_register(), handle_request_subscribe(), and initialize_initreq().

00230 {
00231    dialog->initreq = req;
00232    ast_set_flag(dialog->initreq, SIP_PKT_INITREQ);
00233    
00234 }

struct sip_dialog* sip_alloc ast_string_field  callid,
struct sockaddr_in *  sin,
int  useglobal_nat,
const int  intended_method
 

Allocate SIP_PVT structure and set defaults.

Definition at line 803 of file sip3_dialog.c.

References sip_network::__ourip, sip_globals::allowtransfer, ast_calloc, ast_copy_flags, ast_log(), ast_mutex_destroy(), ast_mutex_init(), AST_RTP_DTMF, ast_set2_flag, ast_string_field_init, ast_string_field_set, ast_test_flag, ast_variables_destroy(), build_callid_pvt(), build_via(), sip_globals::capability, context, sip_globals::default_context, sip_globals::default_fromdomain, sip_globals::default_mohinterpret, sip_globals::default_mohsuggest, sip_globals::default_prefs, dialog_activate_media(), channel_counters::dialog_objects, DIALOG_STATE_TRYING, dialoglist, dialoglist_lock(), dialoglist_unlock(), dialogstatechange(), do_setnat(), sip_globals::flags, free, global, INITIAL_CSEQ, LOG_DEBUG, make_our_tag(), mohinterpret, mohsuggest, NONE, option_debug, sip_globals::recordhistory, SIP_DTMF, SIP_DTMF_AUTO, SIP_DTMF_RFC2833, SIP_FLAGS_TO_COPY, sip_method2txt(), sip_method_needrtp(), SIP_NAT, SIP_NAT_ROUTE, SIP_NO_HISTORY, SIP_OPTIONS, sip_ouraddrfor(), SIP_PAGE2_FLAGS_TO_COPY, SIP_REGISTER, sipcounters, sipnet, sip_globals::t1default, and TRUE.

00805 {
00806    struct sip_dialog *dialog;
00807 
00808    if (!(dialog = ast_calloc(1, sizeof(*dialog))))
00809       return NULL;
00810 
00811    if (ast_string_field_init(dialog, 512)) {
00812       free(dialog);
00813       return NULL;
00814    }
00815    sipcounters.dialog_objects++;
00816    if (option_debug > 3)
00817       ast_log(LOG_DEBUG, "--DIALOGS-- Counter %d\n", sipcounters.dialog_objects);
00818 
00819       ast_mutex_init(&dialog->lock);
00820 
00821    dialog->method = intended_method;
00822    dialog->initid = -1;
00823    dialog->autokillid = -1;
00824    dialog->subscribed = NONE;
00825    dialog->stateid = -1;
00826    dialog->prefs = global.default_prefs;     /* Set default codecs for this call */
00827 
00828    if (intended_method != SIP_OPTIONS) /* Peerpoke has it's own system */
00829       dialog->timer_t1 = global.t1default;   /* 500 ms Default SIP retransmission timer T1 (RFC 3261) */
00830 
00831    if (sin) {
00832       dialog->sa = *sin;
00833       if (sip_ouraddrfor(&dialog->sa.sin_addr, &dialog->ourip))
00834          dialog->ourip = sipnet.__ourip;
00835    } else
00836       dialog->ourip = sipnet.__ourip;
00837 
00838    /* Copy global flags to this PVT at setup. */
00839    ast_copy_flags(&dialog->flags[0], &global.flags[0], SIP_FLAGS_TO_COPY);
00840    ast_copy_flags(&dialog->flags[1], &global.flags[1], SIP_PAGE2_FLAGS_TO_COPY);
00841 
00842    ast_set2_flag(&dialog->flags[0], !global.recordhistory, SIP_NO_HISTORY);
00843 
00844    make_our_tag(dialog->tag, sizeof(dialog->tag));
00845    dialog->ocseq = INITIAL_CSEQ;
00846 
00847    /* Activate media streams */
00848    if (sip_method_needrtp(intended_method)) {
00849       if (!dialog_activate_media(dialog, &sipnet)) {
00850          ast_mutex_destroy(&dialog->lock);
00851          if (dialog->chanvars) {
00852             ast_variables_destroy(dialog->chanvars);
00853             dialog->chanvars = NULL;
00854          }
00855          free(dialog);
00856          return NULL;
00857       }
00858    }
00859 
00860    if (useglobal_nat && sin) {
00861       /* Setup NAT structure according to global settings if we have an address */
00862       ast_copy_flags(&dialog->flags[0], &global.flags[0], SIP_NAT);
00863       dialog->recv = *sin;
00864       do_setnat(dialog, ast_test_flag(&dialog->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
00865    }
00866 
00867    if (dialog->method != SIP_REGISTER)
00868       ast_string_field_set(dialog, fromdomain, global.default_fromdomain);
00869 
00870    build_via(dialog, TRUE);
00871    if (!callid)               /* Make sure we have a unique call ID */
00872       build_callid_pvt(dialog);
00873    else
00874       ast_string_field_set(dialog, callid, callid);
00875 
00876    dialogstatechange(dialog, DIALOG_STATE_TRYING); /* Set dialog state */
00877 
00878                      /* Assign default music on hold class */
00879    ast_string_field_set(dialog, mohinterpret, global.default_mohinterpret);
00880    ast_string_field_set(dialog, mohsuggest, global.default_mohsuggest);
00881    
00882    dialog->capability = global.capability;      /* Set default codec settings */
00883 
00884    if ((ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
00885        (ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
00886       dialog->noncodeccapability |= AST_RTP_DTMF;
00887 
00888    ast_string_field_set(dialog, context, global.default_context);
00889    dialog->allowtransfer = global.allowtransfer;   /* Default transfer mode */
00890 
00891    /* Add to active dialog list */
00892    dialoglist_lock();
00893    dialog->next = dialoglist;
00894    dialoglist = dialog;
00895    dialoglist_unlock();
00896    if (option_debug)
00897       ast_log(LOG_DEBUG, "Allocating new SIP dialog for %s - %s (%s)\n", callid ? callid : "(No Call-ID)", sip_method2txt(intended_method), dialog->rtp ? "With RTP" : "No RTP");
00898    return dialog;
00899 }

GNURK void sip_cancel_destroy struct sip_dialog p  ) 
 

Cancel destruction of SIP dialog.

Definition at line 554 of file sip3_dialog.c.

References append_history, ast_sched_del(), and sip_dialog::autokillid.

00555 {
00556    if (p->autokillid > -1) {
00557       ast_sched_del(sched, p->autokillid);
00558       append_history(p, "CancelDestroy", "");
00559       p->autokillid = -1;
00560    }
00561 }

void sip_destroy struct sip_dialog dialog  ) 
 

Destroy SIP call structure.

Definition at line 486 of file sip3_dialog.c.

References __sip_destroy(), ast_log(), LOG_DEBUG, option_debug, and TRUE.

00487 {
00488    if (option_debug > 2)
00489       ast_log(LOG_DEBUG, "Destroying SIP dialog %s\n", dialog->callid);
00490    __sip_destroy(dialog, TRUE, TRUE);
00491 }

GNURK void sip_scheddestroy struct sip_dialog p,
int  ms
 

Schedule destruction of SIP dialog.

Definition at line 536 of file sip3_dialog.c.

References __sip_autodestruct(), append_history, ast_sched_add(), ast_sched_del(), ast_test_flag, ast_verbose(), sip_dialog::flags, sip_dialog::method, sip_debug_test_pvt(), sip_method2txt(), SIP_NO_HISTORY, and sip_dialog::timer_t1.

00537 {
00538    if (ms < 0) {
00539       if (p->timer_t1 == 0)
00540          p->timer_t1 = 500;   /* Set timer T1 if not set (RFC 3261) */
00541       ms = p->timer_t1 * 64;
00542    }
00543    if (sip_debug_test_pvt(p))
00544       ast_verbose("Scheduling destruction of SIP dialog '%s' in %d ms (Method: %s)\n", p->callid, ms, sip_method2txt(p->method));
00545    if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
00546       append_history(p, "SchedDestroy", "%d ms", ms);
00547 
00548    if (p->autokillid > -1)
00549       ast_sched_del(sched, p->autokillid);
00550    p->autokillid = ast_sched_add(sched, ms, __sip_autodestruct, p);
00551 }

static void temp_pvt_cleanup void *  data  )  [static]
 

Cleanup temporary PVT.

Definition at line 911 of file sip3_dialog.c.

References ast_string_field_free_pools, and free.

00912 {
00913    struct sip_dialog *p = data;
00914 
00915    ast_string_field_free_pools(p);
00916 
00917    free(data);
00918 }

static int temp_pvt_init void *  data  )  [static]
 

Initialize temporary PVT.

Definition at line 902 of file sip3_dialog.c.

References ast_set_flag, ast_string_field_init, sip_dialog::flags, and SIP_NO_HISTORY.

00903 {
00904    struct sip_dialog *p = data;
00905 
00906    ast_set_flag(&p->flags[0], SIP_NO_HISTORY);
00907    return ast_string_field_init(p, 512);
00908 }

int transmit_final_response struct sip_dialog dialog,
const char *  msg,
struct sip_request req,
enum xmittype  reliable
 

Transmit final response to a request and close dialog Set dialog state to TERMINATED to avoid problems At some point, after debugging, we can remove the reliable flag. Only responses to INVITEs are sent reliably.

Definition at line 213 of file sip3_dialog.c.

References __transmit_response(), ast_log(), DIALOG_STATE_TERMINATED, dialogstatechange(), LOG_WARNING, sip_request::method, SIP_INVITE, sip_method2txt(), sip_scheddestroy(), and XMIT_RELIABLE.

Referenced by handle_request_info(), handle_request_invite(), handle_request_message(), handle_request_subscribe(), and sip_indicate().

00214 {
00215    int res;
00216 
00217    /* If this is a final response to an INVITE */
00218    if (reliable == XMIT_RELIABLE && req->method != SIP_INVITE)
00219       ast_log(LOG_WARNING, "Transmitting RELIABLE response to %s - Call ID %s (?? BUG ?? ) \n", sip_method2txt(req->method), dialog->callid);
00220    res = __transmit_response(dialog, msg, req, reliable);
00221    sip_scheddestroy(dialog, -1); /* Destroy by using T1 timer if available */
00222    dialogstatechange(dialog, DIALOG_STATE_TERMINATED);
00223    return res;
00224 }

static int transmit_response_using_temp ast_string_field  callid,
struct sockaddr_in *  sin,
int  useglobal_nat,
const int  intended_method,
struct sip_request req,
const char *  msg
[static]
 

Transmit response, no retransmits, using a temporary pvt structure.

Definition at line 921 of file sip3_dialog.c.

References sip_network::__ourip, __transmit_response(), ast_copy_flags, ast_log(), ast_set_flag, ast_string_field_free_all, ast_string_field_init, ast_string_field_set, ast_test_flag, build_via(), sip_globals::default_fromdomain, do_setnat(), sip_globals::flags, global, INITIAL_CSEQ, LOG_NOTICE, make_our_tag(), SIP_NAT, SIP_NAT_ROUTE, SIP_NO_HISTORY, sip_ouraddrfor(), sipnet, TRUE, and XMIT_UNRELIABLE.

00922 {
00923    struct sip_dialog *p = NULL;
00924 
00925    if (!(p = ast_threadstorage_get(&ts_temp_pvt, sizeof(*p)))) {
00926       ast_log(LOG_NOTICE, "Failed to get temporary pvt\n");
00927       return -1;
00928    }
00929 
00930    /* if the structure was just allocated, initialize it */
00931    if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) {
00932       ast_set_flag(&p->flags[0], SIP_NO_HISTORY);
00933       if (ast_string_field_init(p, 512))
00934          return -1;
00935    }
00936 
00937    /* Initialize the bare minimum */
00938    p->method = intended_method;
00939 
00940    if (sin) {
00941       p->sa = *sin;
00942       if (sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
00943          p->ourip = sipnet.__ourip;
00944    } else
00945       p->ourip = sipnet.__ourip;
00946 
00947    make_our_tag(p->tag, sizeof(p->tag));
00948    p->ocseq = INITIAL_CSEQ;
00949 
00950    if (useglobal_nat && sin) {
00951       ast_copy_flags(&p->flags[0], &global.flags[0], SIP_NAT);
00952       p->recv = *sin;
00953       do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
00954    }
00955 
00956    ast_string_field_set(p, fromdomain, global.default_fromdomain);
00957    build_via(p, TRUE);
00958    ast_string_field_set(p, callid, callid);
00959 
00960    /* Use this temporary pvt structure to send the message */
00961    __transmit_response(p, msg, req, XMIT_UNRELIABLE);
00962 
00963    /* Free the string fields, but not the pool space */
00964    ast_string_field_free_all(p);
00965 
00966    return 0;
00967 }


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen