![]() |
Home page |
Mailing list |
Docs
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