Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:57 2007

Asterisk developer's documentation :: Codename Pineapple


sip3_pokedevice.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  * and Edvina AB, Sollentuna, Sweden (chan_sip3 changes/additions)
00006  *
00007  * Mark Spencer <markster@digium.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*!
00021  * \file
00022  * \brief SIP qualification subsystem - poking around on the network
00023  * Version 3 of chan_sip
00024  *
00025  * \author Mark Spencer <markster@digium.com>
00026  * \author Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)
00027  *
00028  * See Also:
00029  * \arg \ref AstCREDITS
00030  *
00031  */
00032 
00033 #include "asterisk.h"
00034 
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 53128 $")
00036 
00037 #include <stdio.h>
00038 #include <ctype.h>
00039 #include <string.h>
00040 #include <unistd.h>
00041 #include <sys/socket.h>
00042 #include <sys/ioctl.h>
00043 #include <net/if.h>
00044 #include <errno.h>
00045 #include <stdlib.h>
00046 #include <fcntl.h>
00047 #include <netdb.h>
00048 #include <signal.h>
00049 #include <sys/signal.h>
00050 #include <netinet/in.h>
00051 #include <netinet/in_systm.h>
00052 #include <arpa/inet.h>
00053 #include <netinet/ip.h>
00054 #include <regex.h>
00055 
00056 #include "asterisk/lock.h"
00057 #include "asterisk/channel.h"
00058 #include "asterisk/config.h"
00059 #include "asterisk/logger.h"
00060 #include "asterisk/module.h"
00061 #include "asterisk/pbx.h"
00062 #include "asterisk/options.h"
00063 #include "asterisk/sched.h"
00064 #include "asterisk/io.h"
00065 #include "asterisk/rtp.h"
00066 #include "asterisk/udptl.h"
00067 #include "asterisk/acl.h"
00068 #include "asterisk/manager.h"
00069 #include "asterisk/callerid.h"
00070 #include "asterisk/cli.h"
00071 #include "asterisk/app.h"
00072 #include "asterisk/musiconhold.h"
00073 #include "asterisk/dsp.h"
00074 #include "asterisk/features.h"
00075 #include "asterisk/srv.h"
00076 #include "asterisk/astdb.h"
00077 #include "asterisk/causes.h"
00078 #include "asterisk/utils.h"
00079 #include "asterisk/file.h"
00080 #include "asterisk/astobj.h"
00081 #include "asterisk/dnsmgr.h"
00082 #include "asterisk/devicestate.h"
00083 #include "asterisk/linkedlists.h"
00084 #include "asterisk/stringfields.h"
00085 #include "asterisk/monitor.h"
00086 #include "asterisk/localtime.h"
00087 #include "asterisk/abstract_jb.h"
00088 #include "asterisk/compiler.h"
00089 #include "sip3.h"
00090 #include "sip3funcs.h"
00091 
00092 /*! \brief Poke peer (send qualify to check if peer is alive and well) */
00093 int sip_poke_peer_s(void *data)
00094 {
00095    struct sip_device *peer = data;
00096 
00097    peer->pokeexpire = -1;
00098    sip_poke_peer(peer);
00099    return 0;
00100 }
00101 
00102 /*! \brief Handle qualification responses (OPTIONS) */
00103 void handle_response_peerpoke(struct sip_dialog *p, int resp, struct sip_request *req)
00104 {
00105    struct sip_device *peer = p->relatedpeer;
00106    int statechanged, is_reachable, was_reachable;
00107    int pingtime = ast_tvdiff_ms(ast_tvnow(), peer->ps);
00108       
00109    if (!peer)
00110       return;
00111 
00112    /*
00113     * Compute the response time to a ping (goes in peer->lastms.)
00114     * -1 means did not respond, 0 means unknown,
00115     * 1..maxms is a valid response, >maxms means late response.
00116     */
00117    if (pingtime < 1) /* zero = unknown, so round up to 1 */
00118       pingtime = 1;
00119 
00120    /* Now determine new state and whether it has changed.
00121     * Use some helper variables to simplify the writing
00122     * of the expressions.
00123     */
00124    was_reachable = peer->lastms > 0 && peer->lastms <= peer->maxms;
00125    is_reachable = pingtime <= peer->maxms;
00126    statechanged = peer->lastms == 0 /* yes, unknown before */
00127       || was_reachable != is_reachable;
00128 
00129    peer->lastms = pingtime;
00130    peer->call = NULL;
00131    if (statechanged) {
00132       const char *s = is_reachable ? "Reachable" : "Lagged";
00133 
00134       ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n",
00135          peer->name, s, pingtime, peer->maxms);
00136       ast_device_state_changed("SIP/%s", peer->name);
00137       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus",
00138          "Peer: SIP/%s\r\nPeerStatus: %s\r\nTime: %d\r\n",
00139          peer->name, s, pingtime);
00140    }
00141 
00142    if (peer->pokeexpire > -1)
00143       ast_sched_del(sched, peer->pokeexpire);
00144 
00145    /* Try again eventually */
00146    peer->pokeexpire = ast_sched_add(sched,
00147       is_reachable ? global.default_qualifycheck_ok: global.default_qualifycheck_notok,
00148       sip_poke_peer_s, peer);
00149 
00150    dialogstatechange(p, DIALOG_STATE_TERMINATED);
00151    ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); 
00152 }
00153 
00154 /*! \brief React to lack of answer to Qualify poke */
00155 int sip_poke_noanswer(void *data)
00156 {
00157    struct sip_device *peer = data;
00158    
00159    peer->pokeexpire = -1;
00160    if (peer->lastms > -1) {
00161       ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE!  Last qualify: %d\n", peer->name, peer->lastms);
00162       manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, -1);
00163    }
00164    if (peer->call)
00165       sip_destroy(peer->call);
00166    peer->call = NULL;
00167    peer->lastms = -1;
00168    ast_device_state_changed("SIP/%s", peer->name);
00169    /* Try again quickly */
00170    peer->pokeexpire = ast_sched_add(sched, global.default_qualifycheck_notok, sip_poke_peer_s, peer);
00171    return 0;
00172 }
00173 
00174 /*! \brief Check availability of peer, also keep NAT open
00175 \note This is done with the interval in qualify= configuration option
00176    Default is 2 seconds */
00177 int sip_poke_peer(struct sip_device *peer)
00178 {
00179    struct sip_dialog *p;
00180 
00181    if (!peer->maxms || !peer->addr.sin_addr.s_addr) {
00182       /* IF we have no IP, or this isn't to be monitored, return
00183         imeediately after clearing things out */
00184       if (peer->pokeexpire > -1)
00185          ast_sched_del(sched, peer->pokeexpire);
00186       peer->lastms = 0;
00187       peer->pokeexpire = -1;
00188       peer->call = NULL;
00189       return 0;
00190    }
00191    if (peer->call > 0) {
00192       if (sipdebug)
00193          ast_log(LOG_NOTICE, "Still have a QUALIFY dialog active, deleting\n");
00194       sip_destroy(peer->call);
00195    }
00196    if (!(p = peer->call = sip_alloc(NULL, NULL, FALSE, SIP_OPTIONS)))
00197       return -1;
00198    
00199    p->sa = peer->addr;
00200    p->recv = peer->addr;
00201    ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
00202    ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
00203 
00204    /* Send OPTIONs to peer's fullcontact */
00205    if (!ast_strlen_zero(peer->fullcontact))
00206       ast_string_field_set(p, fullcontact, peer->fullcontact);
00207 
00208    if (!ast_strlen_zero(peer->extra.tohost))
00209       ast_string_field_set(p, tohost, peer->extra.tohost);
00210    else
00211       ast_string_field_set(p, tohost, ast_inet_ntoa(peer->addr.sin_addr));
00212 
00213    /* Recalculate our side, and recalculate Call ID */
00214    if (sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
00215       p->ourip = sipnet.__ourip;
00216    build_via(p, FALSE);
00217    build_callid_pvt(p);
00218 
00219    if (peer->pokeexpire > -1)
00220       ast_sched_del(sched, peer->pokeexpire);
00221    p->relatedpeer = peer;
00222    ast_set_flag(&p->flags[0], SIP_OUTGOING);
00223 #ifdef VOCAL_DATA_HACK
00224    ast_copy_string(p->peername, "__VOCAL_DATA_SHOULD_READ_THE_SIP_SPEC__", sizeof(p->peername));
00225    transmit_invite(p, SIP_INVITE, FALSE, 2);
00226 #else
00227    transmit_invite(p, SIP_OPTIONS, FALSE, 2);
00228 #endif
00229    gettimeofday(&peer->ps, NULL);
00230    peer->pokeexpire = ast_sched_add(sched, DEFAULT_QUALIFY_MAXMS * 2, sip_poke_noanswer, peer);
00231 
00232    return 0;
00233 }
00234 
00235 /*! \brief Send a poke to all known peers 
00236    Space them out 100 ms apart
00237    XXX We might have a cool algorithm for this or use random - any suggestions?
00238 */
00239 void sip_poke_all_peers(void)
00240 {
00241    int ms = 0;
00242    
00243    if (!sipcounters.static_peers)   /* No peers, just give up */
00244       return;
00245 
00246    ASTOBJ_CONTAINER_TRAVERSE(&devicelist, 1, do {
00247       ASTOBJ_WRLOCK(iterator);
00248       if (iterator->pokeexpire > -1)
00249          ast_sched_del(sched, iterator->pokeexpire);
00250       ms += 100;
00251       iterator->pokeexpire = ast_sched_add(sched, ms, sip_poke_peer_s, iterator);
00252       ASTOBJ_UNLOCK(iterator);
00253    } while (0)
00254    );
00255 }
00256 

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