Codename Pineapple

Home page | Mailing list | Docs

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

Asterisk developer's documentation :: Codename Pineapple


sip3_services.c File Reference


Detailed Description

Various SIP functions for services, registrations for SIP service with other providers/servers 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_services.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 <sys/signal.h>
#include <net/if.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <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/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/acl.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.h"
#include "sip3funcs.h"

Include dependency graph for sip3_services.c:

Go to the source code of this file.

Functions

static int __sip_do_register (struct sip_registry *r)
 Register with SIP proxy.
static void build_callid_registry (struct sip_registry *reg, struct in_addr ourip, const char *fromdomain)
 Build SIP Call-ID value for a REGISTER transaction.
int handle_response_register (struct sip_dialog *p, int resp, char *rest, struct sip_request *req, int seqno)
 Handle responses on REGISTER to services.
char * regstate2str (enum sipregistrystate regstate)
 Convert registration state status to string.
static int sip_reg_timeout (void *data)
 Registration timeout, register again.
int sip_register (char *value, int lineno, struct sip_device *peer)
 Parse register=> line in sip.conf and add to registry.
void sip_registry_destroy (struct sip_registry *reg)
 Destroy registry object Objects created with the register= statement in static configuration.
static int sip_reregister (void *data)
 Update registration with SIP Proxy.
void sip_send_all_registers (void)
 Send all known registrations.
int transmit_register (struct sip_registry *r, int sipmethod, const char *auth, const char *authheader)
 Transmit register to SIP proxy or UA.

Variables

sip_register_list regl
 The register list: Other SIP proxys we register with and place calls to.


Function Documentation

static int __sip_do_register struct sip_registry r  )  [static]
 

Register with SIP proxy.

Definition at line 298 of file sip3_services.c.

References SIP_REGISTER, and transmit_register().

00299 {
00300    int res;
00301 
00302    res = transmit_register(r, SIP_REGISTER, NULL, NULL);
00303    return res;
00304 }

static void build_callid_registry struct sip_registry reg,
struct in_addr  ourip,
const char *  fromdomain
[static]
 

Build SIP Call-ID value for a REGISTER transaction.

Definition at line 126 of file sip3_services.c.

References ast_inet_ntoa(), ast_string_field_build, generate_random_string(), and S_OR.

00127 {
00128    char buf[33];
00129 
00130    const char *host = S_OR(fromdomain, ast_inet_ntoa(ourip));
00131 
00132    ast_string_field_build(reg, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
00133 }

int handle_response_register struct sip_dialog p,
int  resp,
char *  rest,
struct sip_request req,
int  seqno
 

Handle responses on REGISTER to services.

Definition at line 556 of file sip3_services.c.

References __get_header(), ast_log(), ast_sched_del(), ast_set_flag, ast_strlen_zero(), sip_dialog::authtries, sip_registry::call, DEFAULT_TRANS_TIMEOUT, do_register_auth(), EVENT_FLAG_SYSTEM, sip_registry::expire, sip_registry::expiry, expiry, sip_dialog::flags, get_header(), global, sip_dialog::initreq, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, manager_event, MAX_AUTHTRIES, option_debug, REG_STATE_REGISTERED, REG_STATE_REJECTED, REG_STATE_UNREGISTERED, sip_registry::regattempts, sip_globals::regattempts_max, sip_dialog::registry, sip_registry::regstate, regstate2str(), sip_registry::regtime, SIP_NEEDDESTROY, SIP_REGISTER, sip_scheddestroy(), sip_registry::timeout, and transmit_register().

00557 {
00558    int expires, expires_ms;
00559    struct sip_registry *r;
00560    r = p->registry;
00561 
00562    switch (resp) {
00563    case 401:   /* Unauthorized */
00564       if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) {
00565          ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s@%s' (Tries %d)\n", p->registry->username, p->registry->hostname, p->authtries);
00566          ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00567          }
00568       break;
00569    case 403:   /* Forbidden */
00570       ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname);
00571       if (global.regattempts_max)
00572          p->registry->regattempts = global.regattempts_max+1;
00573       ast_sched_del(sched, r->timeout);
00574       ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00575       break;
00576    case 404:   /* Not found */
00577       ast_log(LOG_WARNING, "Got 404 Not found on SIP register to service %s@%s, giving up\n", p->registry->username, p->registry->hostname);
00578       if (global.regattempts_max)
00579          p->registry->regattempts = global.regattempts_max+1;
00580       ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00581       r->call = NULL;
00582       ast_sched_del(sched, r->timeout);
00583       break;
00584    case 407:   /* Proxy auth */
00585       if (p->authtries == MAX_AUTHTRIES || do_register_auth(p, req, resp)) {
00586          ast_log(LOG_NOTICE, "Failed to authenticate on REGISTER to '%s' (tries '%d')\n", get_header(p->initreq, "From"), p->authtries);
00587          ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00588       }
00589       break;
00590    case 423:   /* Interval too brief */
00591       r->expiry = atoi(get_header(req, "Min-Expires"));
00592       ast_log(LOG_WARNING, "Got 423 Interval too brief for service %s@%s, minimum is %d seconds\n", p->registry->username, p->registry->hostname, r->expiry);
00593       ast_sched_del(sched, r->timeout);
00594       r->timeout = -1;
00595       if (r->call) {
00596          r->call = NULL;
00597          ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00598       }
00599       if (r->expiry > expiry.max_expiry) {
00600          ast_log(LOG_WARNING, "Required expiration time from %s@%s is too high, giving up\n", p->registry->username, p->registry->hostname);
00601          r->expiry = expiry.default_expiry;
00602          r->regstate = REG_STATE_REJECTED;
00603       } else {
00604          r->regstate = REG_STATE_UNREGISTERED;
00605          transmit_register(r, SIP_REGISTER, NULL, NULL);
00606       }
00607       manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
00608       break;
00609    case 479:   /* SER: Not able to process the URI - address is wrong in register*/
00610       ast_log(LOG_WARNING, "Got error 479 on register to %s@%s, giving up (check config)\n", p->registry->username,p->registry->hostname);
00611       if (global.regattempts_max)
00612          p->registry->regattempts = global.regattempts_max+1;
00613       ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00614       r->call = NULL;
00615       ast_sched_del(sched, r->timeout);
00616       break;
00617    case 200:   /* 200 OK */
00618       p->authtries = 0;
00619       if (!r) {
00620          ast_log(LOG_WARNING, "Got 200 OK on REGISTER that isn't a register\n");
00621          ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00622          return 0;
00623       }
00624 
00625       r->regstate = REG_STATE_REGISTERED;
00626       r->regtime = time(NULL);      /* Reset time of last succesful registration */
00627       manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: SIP\r\nDomain: %s\r\nStatus: %s\r\n", r->hostname, regstate2str(r->regstate));
00628       r->regattempts = 0;
00629       if (option_debug)
00630          ast_log(LOG_DEBUG, "Registration successful\n");
00631       if (r->timeout > -1) {
00632          if (option_debug)
00633             ast_log(LOG_DEBUG, "Cancelling timeout %d\n", r->timeout);
00634          ast_sched_del(sched, r->timeout);
00635       }
00636       r->timeout=-1;
00637       r->call = NULL;
00638       p->registry = NULL;
00639       /* Let this one hang around until we have all the responses */
00640       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
00641       /* ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); */
00642 
00643       /* set us up for re-registering */
00644       /* figure out how long we got registered for */
00645       if (r->expire > -1)
00646          ast_sched_del(sched, r->expire);
00647       /* according to section 6.13 of RFC, contact headers override
00648          expires headers, so check those first */
00649       expires = 0;
00650 
00651       /* XXX todo: try to save the extra call */
00652       if (!ast_strlen_zero(get_header(req, "Contact"))) {
00653          const char *contact = NULL;
00654          const char *tmptmp = NULL;
00655          int start = 0;
00656          for(;;) {
00657             contact = __get_header(req, "Contact", &start);
00658             /* this loop ensures we get a contact header about our register request */
00659             if(!ast_strlen_zero(contact)) {
00660                if( (tmptmp=strstr(contact, p->our_contact))) {
00661                   contact=tmptmp;
00662                   break;
00663                }
00664             } else
00665                break;
00666          }
00667          tmptmp = strcasestr(contact, "expires=");
00668          if (tmptmp) {
00669             if (sscanf(tmptmp + 8, "%d;", &expires) != 1)
00670                expires = 0;
00671          }
00672 
00673       }
00674       if (!expires) 
00675          expires = atoi(get_header(req, "expires"));
00676       if (!expires)
00677          expires = expiry.default_expiry;
00678 
00679       expires_ms = expires * 1000;
00680       if (expires <= EXPIRY_GUARD_LIMIT)
00681          expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT),EXPIRY_GUARD_MIN);
00682       else
00683          expires_ms -= EXPIRY_GUARD_SECS * 1000;
00684       if (sipdebug)
00685          ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d s)\n", r->hostname, expires, expires_ms/1000); 
00686 
00687       r->refresh= (int) expires_ms / 1000;
00688 
00689       /* Schedule re-registration before we expire */
00690       r->expire = ast_sched_add(sched, expires_ms, sip_reregister, r); 
00691       ASTOBJ_UNREF(r, sip_registry_destroy);
00692    }
00693    return 1;
00694 }

char* regstate2str enum sipregistrystate  regstate  ) 
 

Convert registration state status to string.

Definition at line 101 of file sip3_services.c.

References REG_STATE_AUTHSENT, REG_STATE_FAILED, REG_STATE_NOAUTH, REG_STATE_REGISTERED, REG_STATE_REGSENT, REG_STATE_REJECTED, REG_STATE_TIMEOUT, and REG_STATE_UNREGISTERED.

00102 {
00103    switch(regstate) {
00104    case REG_STATE_FAILED:
00105       return "Failed";
00106    case REG_STATE_UNREGISTERED:
00107       return "Unregistered";
00108    case REG_STATE_REGSENT:
00109       return "Request Sent";
00110    case REG_STATE_AUTHSENT:
00111       return "Auth. Sent";
00112    case REG_STATE_REGISTERED:
00113       return "Registered";
00114    case REG_STATE_REJECTED:
00115       return "Rejected";
00116    case REG_STATE_TIMEOUT:
00117       return "Timeout";
00118    case REG_STATE_NOAUTH:
00119       return "No Authentication";
00120    default:
00121       return "Unknown";
00122    }
00123 }

static int sip_reg_timeout void *  data  )  [static]
 

Registration timeout, register again.

Definition at line 330 of file sip3_services.c.

References __sip_pretend_ack(), ast_log(), ast_set_flag, ASTOBJ_REF, ASTOBJ_UNREF, sip_registry::call, EVENT_FLAG_SYSTEM, sip_dialog::flags, global, LOG_NOTICE, manager_event, REG_STATE_FAILED, REG_STATE_UNREGISTERED, sip_registry::regattempts, sip_globals::regattempts_max, sip_dialog::registry, sip_registry::regstate, regstate2str(), SIP_NEEDDESTROY, SIP_REGISTER, sip_registry_destroy(), sip_registry::timeout, and transmit_register().

00331 {
00332 
00333    /* if we are here, our registration timed out, so we'll just do it over */
00334    struct sip_registry *r = ASTOBJ_REF((struct sip_registry *) data);
00335    struct sip_dialog *p;
00336    int res;
00337 
00338    /* if we couldn't get a reference to the registry object, punt */
00339    if (!r)
00340       return 0;
00341 
00342    ast_log(LOG_NOTICE, "   -- Registration for '%s@%s' timed out, trying again (Attempt #%d)\n", r->username, r->hostname, r->regattempts); 
00343    if (r->call) {
00344       /* Unlink us, destroy old call.  Locking is not relevant here because all this happens
00345          in the single SIP manager thread. */
00346       p = r->call;
00347       if (p->registry)
00348          ASTOBJ_UNREF(p->registry, sip_registry_destroy);
00349       r->call = NULL;
00350       ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00351       /* Pretend to ACK anything just in case */
00352       __sip_pretend_ack(p); /* XXX we need p locked, not sure we have */
00353    }
00354    /* If we have a limit, stop registration and give up */
00355    if (global.regattempts_max && (r->regattempts > global.regattempts_max)) {
00356       /* Ok, enough is enough. Don't try any more */
00357       /* We could add an external notification here... 
00358          steal it from app_voicemail :-) */
00359       ast_log(LOG_NOTICE, "   -- Giving up forever trying to register '%s@%s'\n", r->username, r->hostname);
00360       r->regstate = REG_STATE_FAILED;
00361    } else {
00362       r->regstate = REG_STATE_UNREGISTERED;
00363       r->timeout = -1;
00364       res = transmit_register(r, SIP_REGISTER, NULL, NULL);
00365    }
00366    manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
00367    ASTOBJ_UNREF(r, sip_registry_destroy);
00368    return 0;
00369 }

int sip_register char *  value,
int  lineno,
struct sip_device peer
 

Parse register=> line in sip.conf and add to registry.

Definition at line 161 of file sip3_services.c.

References ast_calloc, ast_log(), ast_string_field_build, ast_string_field_init, ast_string_field_set, ast_strlen_zero(), ASTOBJ_CONTAINER_LINK, ASTOBJ_INIT, ASTOBJ_UNREF, expiry, sip_device::extra, FALSE, free, generate_random_string(), hostname, INITIAL_CSEQ, LOG_ERROR, LOG_WARNING, sip_registry::peer, REG_MAGICMARKER, sip_device::registry, channel_counters::registry_objects, regl, secret, sip_registry_destroy(), sipcounters, sipdebug, and sip_device_extra::tohost.

00162 {
00163    struct sip_registry *reg;
00164    char username[256] = "";
00165    char randomcontact[256];
00166    char *hostname = NULL, *secret = NULL, *authuser = NULL;
00167    char *porta = NULL;
00168    char *contact = NULL;
00169    char *extension = NULL;
00170    int portnum = 0;
00171    
00172    if (peer != NULL) {  /* Build registration string from peer info */
00173       /* Need to copy port number as well */
00174       if (ast_strlen_zero(peer->extra.fromuser))
00175          snprintf(username, sizeof(username), "%s:%s@%s/%s",
00176             peer->name, peer->secret, peer->extra.tohost, peer->extra.regexten);
00177       else
00178          snprintf(username, sizeof(username), "%s:%s:%s@%s/%s",
00179             peer->name, peer->secret, peer->extra.fromuser, peer->extra.tohost, peer->extra.regexten);
00180    } else if (value)
00181       ast_copy_string(username, value, sizeof(username));
00182    else
00183       username[0] = '\0';
00184 
00185    
00186    /* ------ Parse registration string ----------- */
00187    /* First split around the last '@' then parse the two components. */
00188    hostname = strrchr(username, '@'); /* allow @ in the first part */
00189    if (hostname)
00190       *hostname++ = '\0';
00191    if (ast_strlen_zero(username) || ast_strlen_zero(hostname)) {
00192       ast_log(LOG_WARNING, "Format for registration is user[:secret[:authuser]]@host[:port][/contact] at line %d\n", lineno);
00193       return -1;
00194    }
00195    /* split user[:secret[:authuser]] */
00196    secret = strchr(username, ':');
00197    if (secret) {
00198       *secret++ = '\0';
00199       authuser = strchr(secret, ':');
00200       if (authuser)
00201          *authuser++ = '\0';
00202    }
00203    /* split host[:port][/contact] */
00204    contact = strchr(hostname, '/');
00205    if (contact)
00206       *contact++ = '\0';
00207    if (ast_strlen_zero(contact))
00208       contact = "s";
00209    porta = strchr(hostname, ':');
00210    if (porta) {
00211       *porta++ = '\0';
00212       portnum = atoi(porta);
00213       if (portnum == 0) {
00214          ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
00215          return -1;
00216       }
00217    }
00218 
00219    /* Allocate data */
00220    if (!(reg = ast_calloc(1, sizeof(*reg)))) {
00221       ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n");
00222       return -1;
00223    }
00224 
00225    if (ast_string_field_init(reg, 256)) {
00226       ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry strings\n");
00227       free(reg);
00228       return -1;
00229    }
00230 
00231    if (peer) {
00232       reg->peer = peer;
00233       peer->registry = reg;
00234       // xxx?? ASTOBJ_REF(peer);    /* Add reference counter to peer */
00235    }
00236 
00237    sipcounters.registry_objects++;
00238    ASTOBJ_INIT(reg);
00239    if (username)
00240       ast_string_field_set(reg, username, username);
00241    if (hostname)
00242       ast_string_field_set(reg, hostname, hostname);
00243    if (authuser)
00244       ast_string_field_set(reg, authuser, authuser);
00245    if (secret)
00246       ast_string_field_set(reg, secret, secret);
00247 
00248    if (extension)
00249       ast_string_field_set(reg, extension, extension);
00250    /* Build a random contact string for this registration entry */
00251    generate_random_string(randomcontact, sizeof(randomcontact));
00252    if (sipdebug)
00253       ast_string_field_build(reg, contact, "%s-%s-%s-debug", REG_MAGICMARKER, randomcontact, extension);
00254    else
00255       ast_string_field_build(reg, contact, "%s-%s", REG_MAGICMARKER, randomcontact);
00256 
00257    reg->expire = -1;
00258    reg->expiry = expiry.default_expiry;
00259    reg->timeout =  -1;
00260    reg->refresh = expiry.default_expiry;
00261    reg->portno = porta ? atoi(porta) : 0;
00262    reg->callid_valid = FALSE;
00263    reg->ocseq = INITIAL_CSEQ;
00264    ASTOBJ_CONTAINER_LINK(&regl, reg);  /* Add the new registry entry to the list */
00265    ASTOBJ_UNREF(reg,sip_registry_destroy);
00266    return 0;
00267 }

void sip_registry_destroy struct sip_registry reg  ) 
 

Destroy registry object Objects created with the register= statement in static configuration.

Definition at line 271 of file sip3_services.c.

References ast_log(), ast_sched_del(), ast_string_field_free_pools, sip_registry::call, sip_registry::expire, free, LOG_DEBUG, option_debug, sip_registry::peer, sip_pvt::registry, sip_device::registry, channel_counters::registry_objects, sip_destroy(), sipcounters, and sip_registry::timeout.

00272 {
00273    /* Really delete */
00274    if (option_debug > 2)
00275       ast_log(LOG_DEBUG, "Destroying registry entry for %s@%s\n", reg->username, reg->hostname);
00276 
00277    if (reg->call) {
00278       /* Clear registry before destroying to ensure
00279          we don't get reentered trying to grab the registry lock */
00280       reg->call->registry = NULL;
00281       if (option_debug > 2)
00282          ast_log(LOG_DEBUG, "Destroying active SIP dialog for registry %s@%s\n", reg->username, reg->hostname);
00283       sip_destroy(reg->call);
00284    }
00285    if (reg->expire > -1)
00286       ast_sched_del(sched, reg->expire);
00287    if (reg->timeout > -1)
00288       ast_sched_del(sched, reg->timeout);
00289    if (reg->peer)
00290       reg->peer->registry = NULL;      /* XXX ASTOBJ_UNREF ??? */
00291    ast_string_field_free_pools(reg);
00292    sipcounters.registry_objects--;
00293    free(reg);
00294    
00295 }

static int sip_reregister void *  data  )  [static]
 

Update registration with SIP Proxy.

Definition at line 307 of file sip3_services.c.

References __sip_do_register(), append_history, ast_log(), ast_test_flag, ASTOBJ_REF, ASTOBJ_UNREF, sip_registry::call, sip_registry::expire, sip_pvt::flags, LOG_NOTICE, SIP_NO_HISTORY, sip_registry_destroy(), and sipdebug.

00308 {
00309    /* if we are here, we know that we need to reregister. */
00310    struct sip_registry *r= ASTOBJ_REF((struct sip_registry *) data);
00311 
00312    /* if we couldn't get a reference to the registry object, punt */
00313    if (!r)
00314       return 0;
00315 
00316    if (r->call && !ast_test_flag(&r->call->flags[0], SIP_NO_HISTORY)) 
00317       append_history(r->call, "RegistryRenew", "Account: %s@%s", r->username, r->hostname);
00318    /* Since registry's are only added/removed by the the monitor thread, this
00319       may be overkill to reference/dereference at all here */
00320    if (sipdebug)
00321       ast_log(LOG_NOTICE, "   -- Re-registration for  %s@%s\n", r->username, r->hostname);
00322 
00323    r->expire = -1;
00324    __sip_do_register(r);
00325    ASTOBJ_UNREF(r, sip_registry_destroy);
00326    return 0;
00327 }

void sip_send_all_registers void   ) 
 

Send all known registrations.

Note:
We space them out not to congest the network and the server

Definition at line 139 of file sip3_services.c.

References ast_sched_add(), ast_sched_del(), ASTOBJ_CONTAINER_TRAVERSE, ASTOBJ_UNLOCK, ASTOBJ_WRLOCK, expiry, channel_counters::registry_objects, regl, sip_reregister(), and sipcounters.

00140 {
00141    int ms;
00142    int regspacing;
00143    if (!sipcounters.registry_objects)
00144       return;
00145    regspacing = expiry.default_expiry * 1000/sipcounters.registry_objects;
00146    if (regspacing > 100)
00147       regspacing = 100;
00148    ms = regspacing;
00149    ASTOBJ_CONTAINER_TRAVERSE(&regl, 1, do {
00150       ASTOBJ_WRLOCK(iterator);
00151       if (iterator->expire > -1)
00152          ast_sched_del(sched, iterator->expire);
00153       ms += regspacing;
00154       iterator->expire = ast_sched_add(sched, ms, sip_reregister, iterator);
00155       ASTOBJ_UNLOCK(iterator);
00156    } while (0)
00157    );
00158 }

int transmit_register struct sip_registry r,
int  sipmethod,
const char *  auth,
const char *  authheader
 

Transmit register to SIP proxy or UA.

Definition at line 372 of file sip3_services.c.

References sip_network::__ourip, add_header(), add_header_contentLength(), append_history, append_maxforwards(), ast_log(), ast_sched_add(), ast_sched_del(), ast_set_flag, ast_string_field_free, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_verbose(), ASTOBJ_REF, sip_network::bindaddr, build_callid_registry(), build_contact(), build_reply_digest(), build_via(), sip_registry::call, sip_registry::callid_valid, create_addr(), sip_globals::default_fromdomain, sip_registry::expiry, exten, sip_device::extra, sip_dialog::flags, sip_request::from, global, sip_request::headers, init_req(), initialize_initreq(), sip_dialog::initreq, sip_request::lines, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, make_our_tag(), sip_dialog::noncecount, sip_registry::noncecount, sip_registry::ocseq, sip_dialog::ocseq, option_debug, sip_registry::peer, sip_registry::portno, REG_STATE_AUTHSENT, REG_STATE_REGSENT, sip_globals::reg_timeout, sip_registry::regattempts, sip_pvt::registry, sip_registry::regstate, S_OR, send_request(), sip_request::seqno, sip_alloc(), sip_debug_test_pvt(), sip_destroy(), SIP_MAX_PACKET, sip_method2txt(), SIP_NO_HISTORY, sip_ouraddrfor(), SIP_OUTGOING, sip_reg_timeout(), SIP_REGISTER, sipdebug, sipnet, siprequest_alloc(), sip_dialog::tag, sip_registry::timeout, sip_request::to, TRUE, sip_globals::useragent, and XMIT_CRITICAL.

00373 {
00374    struct sip_request *req;
00375    char from[256];
00376    char to[256];
00377    char tmp[80];
00378    char addr[80];
00379    struct sip_dialog *dialog;
00380 
00381    req = siprequest_alloc(SIP_MAX_PACKET, &sipnet);
00382 
00383    /* exit if we are already in process with this registrar ?*/
00384    if ( r == NULL || ((auth==NULL) && (r->regstate==REG_STATE_REGSENT || r->regstate==REG_STATE_AUTHSENT))) {
00385       ast_log(LOG_NOTICE, "Strange, trying to register %s@%s when registration already pending\n", r->username, r->hostname);
00386       return 0;
00387    }
00388 
00389    if (r->call) { /* We have a registration */
00390       if (!auth) {
00391          ast_log(LOG_WARNING, "Already have a REGISTER going on to %s@%s?? \n", r->username, r->hostname);
00392          return 0;
00393       } else {
00394          dialog = r->call;
00395          make_our_tag(dialog->tag, sizeof(dialog->tag)); /* create a new local tag for every register attempt */
00396          ast_string_field_free(dialog, theirtag);  /* forget their old tag, so we don't match tags when getting response */
00397       }
00398    } else {
00399       /* Build callid for registration if we haven't registered before */
00400       if (!r->callid_valid) {
00401          build_callid_registry(r, sipnet.__ourip, global.default_fromdomain);
00402          r->callid_valid = TRUE;
00403       }
00404       /* Allocate SIP packet for registration */
00405       if (!(dialog = sip_alloc( r->callid, NULL, 0, SIP_REGISTER))) {
00406          ast_log(LOG_WARNING, "Unable to allocate registration transaction (memory or socket error)\n");
00407          return 0;
00408       }
00409       if (!ast_test_flag(&dialog->flags[0], SIP_NO_HISTORY))
00410          append_history(dialog, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
00411       /* Find address to hostname */
00412       if (create_addr(dialog, NULL, r->hostname, NULL)) {
00413          /* we have what we hope is a temporary network error,
00414           * probably DNS.  We need to reschedule a registration try */
00415          sip_destroy(dialog);
00416          if (r->timeout > -1) {
00417             ast_sched_del(sched, r->timeout);
00418             r->timeout = ast_sched_add(sched, global.reg_timeout*1000, sip_reg_timeout, r);
00419             ast_log(LOG_WARNING, "Still have a registration timeout for %s@%s (create_addr() error), %d\n", r->username, r->hostname, r->timeout);
00420          } else {
00421             r->timeout = ast_sched_add(sched, global.reg_timeout*1000, sip_reg_timeout, r);
00422             ast_log(LOG_WARNING, "Probably a DNS error for registration to %s@%s, trying REGISTER again (after %d seconds)\n", r->username, r->hostname, global.reg_timeout);
00423          }
00424          r->regattempts++;
00425          return 0;
00426       }
00427       /* Copy back Call-ID in case create_addr changed it */
00428       ast_string_field_set(r, callid, dialog->callid);
00429       if (r->portno)
00430          dialog->sa.sin_port = htons(r->portno);
00431       else  /* Set registry port to the port set from the peer definition/srv or default */
00432          r->portno = ntohs(dialog->sa.sin_port);
00433       ast_set_flag(&dialog->flags[0], SIP_OUTGOING);  /* Registration is outgoing call */
00434       r->call = dialog;       /* Save pointer to SIP packet */
00435       dialog->registry = ASTOBJ_REF(r);   /* Add pointer to registry in packet */
00436       if (!ast_strlen_zero(r->secret)) /* Secret (password) */
00437          ast_string_field_set(dialog, peersecret, r->secret);
00438       if (!ast_strlen_zero(r->md5secret))
00439          ast_string_field_set(dialog, peermd5secret, r->md5secret);
00440       /* User name in this realm  
00441       - if authuser is set, use that, otherwise use username */
00442       if (!ast_strlen_zero(r->authuser)) {   
00443          ast_string_field_set(dialog, peername, r->authuser);
00444          ast_string_field_set(dialog, authname, r->authuser);
00445       } else if (!ast_strlen_zero(r->username)) {
00446          ast_string_field_set(dialog, peername, r->username);
00447          ast_string_field_set(dialog, authname, r->username);
00448          ast_string_field_set(dialog, fromuser, r->username);
00449       }
00450       if (!ast_strlen_zero(r->username))
00451          ast_string_field_set(dialog, username, r->username);
00452       /* Save extension in packet */
00453    
00454       /* If we have a peer relationship, fetch som more data from taht peer.
00455       */
00456       if (r->peer) {
00457          if (!ast_strlen_zero(r->peer->extra.fromdomain))
00458             ast_string_field_set(dialog, fromdomain, r->peer->extra.fromdomain);
00459       }
00460       ast_string_field_set(dialog, exten, r->contact);
00461 
00462       /*
00463         check which address we should use in our contact header 
00464         based on whether the remote host is on the external or
00465         internal network so we can register through nat
00466        */
00467       if (sip_ouraddrfor(&dialog->sa.sin_addr, &dialog->ourip))
00468          dialog->ourip = sipnet.bindaddr.sin_addr;
00469       build_contact(dialog);
00470    }
00471 
00472    /* set up a timeout */
00473    if (auth == NULL)  {
00474       if (r->timeout > -1) {
00475          ast_log(LOG_WARNING, "Still have a registration timeout, #%d - deleting it\n", r->timeout);
00476          ast_sched_del(sched, r->timeout);
00477       }
00478       r->timeout = ast_sched_add(sched, global.reg_timeout * 1000, sip_reg_timeout, r);
00479       if (option_debug)
00480          ast_log(LOG_DEBUG, "Scheduled a registration timeout for %s id  #%d \n", r->hostname, r->timeout);
00481    }
00482 
00483    if (strchr(r->username, '@')) {
00484       snprintf(from, sizeof(from), "<sip:%s>;tag=%s", r->username, dialog->tag);
00485       if (!ast_strlen_zero(dialog->theirtag))
00486          snprintf(to, sizeof(to), "<sip:%s>;tag=%s", r->username, dialog->theirtag);
00487       else
00488          snprintf(to, sizeof(to), "<sip:%s>", r->username);
00489    } else {
00490       snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", r->username, dialog->tohost, dialog->tag);
00491       if (!ast_strlen_zero(dialog->theirtag))
00492          snprintf(to, sizeof(to), "<sip:%s@%s>;tag=%s", r->username, dialog->tohost, dialog->theirtag);
00493       else
00494          snprintf(to, sizeof(to), "<sip:%s@%s>", r->username, dialog->tohost);
00495    }
00496    
00497    /* Fromdomain is what we are registering to, regardless of actual
00498       host name from SRV */
00499    snprintf(addr, sizeof(addr), "sip:%s", S_OR(dialog->fromdomain, r->hostname));
00500    ast_string_field_set(dialog, uri, addr);
00501 
00502    init_req(req, sipmethod, addr);
00503 
00504    /* Add to CSEQ */
00505    snprintf(tmp, sizeof(tmp), "%u %s", ++r->ocseq, sip_method2txt(sipmethod));
00506    req->seqno = dialog->ocseq = r->ocseq;
00507    build_via(dialog, TRUE);
00508    add_header(req, "Via", dialog->via);
00509    add_header(req, "From", from);
00510    add_header(req, "To", to);
00511    add_header(req, "Call-ID", dialog->callid);
00512    add_header(req, "CSeq", tmp);
00513    add_header(req, "User-Agent", global.useragent);
00514    append_maxforwards(req);
00515    
00516    if (auth)   /* Add auth header */
00517       add_header(req, authheader, auth);
00518    else if (!ast_strlen_zero(r->nonce)) {
00519       char digest[1024];
00520 
00521       /* We have auth data to reuse, build a digest header! */
00522       if (sipdebug)
00523          ast_log(LOG_DEBUG, "   >>> Re-using Auth data for %s@%s\n", r->username, r->hostname);
00524       ast_string_field_set(dialog, realm, r->realm);
00525       ast_string_field_set(dialog, nonce, r->nonce);
00526       ast_string_field_set(dialog, domain, r->domain);
00527       ast_string_field_set(dialog, opaque, r->opaque);
00528       ast_string_field_set(dialog, qop, r->qop);
00529       dialog->noncecount = r->noncecount++;
00530 
00531       memset(digest, 0, sizeof(digest));
00532       if(!build_reply_digest(dialog, sipmethod, digest, sizeof(digest)))
00533          add_header(req, "Authorization", digest);
00534       else
00535          ast_log(LOG_NOTICE, "No authorization available for authentication of registration to %s@%s\n", r->username, r->hostname);
00536    
00537    }
00538 
00539    snprintf(tmp, sizeof(tmp), "%d", r->expiry);
00540    add_header(req, "Expires", tmp);
00541    add_header(req, "Contact", dialog->our_contact);
00542    add_header(req, "Event", "registration");
00543    add_header_contentLength(req, 0);
00544 
00545    initialize_initreq(dialog, req);
00546    if (sip_debug_test_pvt(dialog))
00547       ast_verbose("REGISTER %d headers, %d lines\n", dialog->initreq->headers, dialog->initreq->lines);
00548    r->regstate = auth ? REG_STATE_AUTHSENT : REG_STATE_REGSENT;
00549    r->regattempts++; /* Another attempt */
00550    if (option_debug > 3)
00551       ast_verbose("REGISTER attempt %d to %s@%s\n", r->regattempts, r->username, r->hostname);
00552    return send_request(dialog, req, XMIT_CRITICAL);
00553 }


Variable Documentation

struct sip_register_list regl
 

The register list: Other SIP proxys we register with and place calls to.

Registration list

Definition at line 98 of file sip3_services.c.


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