Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 168717) +++ channels/chan_sip.c (working copy) @@ -1454,7 +1454,7 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v); /* Realtime device support */ -static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey); +static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey, int lastms); static struct sip_user *realtime_user(const char *username); static void update_peer(struct sip_peer *p, int expiry); static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin, int devstate_only); @@ -2415,18 +2415,20 @@ that name and store that in the "regserver" field in the sippeers table to facilitate multi-server setups. */ -static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey) +static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey, int lastms) { char port[10]; char ipaddr[INET_ADDRSTRLEN]; char regseconds[20]; + char str_lastms[20]; char *sysname = ast_config_AST_SYSTEM_NAME; char *syslabel = NULL; time_t nowtime = time(NULL) + expirey; const char *fc = fullcontact ? "fullcontact" : NULL; - + + snprintf(str_lastms, sizeof(str_lastms), "%d", lastms); snprintf(regseconds, sizeof(regseconds), "%d", (int)nowtime); /* Expiration time */ ast_copy_string(ipaddr, ast_inet_ntoa(sin->sin_addr), sizeof(ipaddr)); snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port)); @@ -2444,6 +2446,9 @@ ast_update_realtime("sippeers", "name", peername, "ipaddr", ipaddr, "port", port, "regseconds", regseconds, "username", username, syslabel, sysname, NULL); /* note syslabel _can_ be NULL */ + /* We cannot do this in the same statement as above, because the lack of + * this field could cause the whole statement to fail. */ + ast_update_realtime("sippeers", "name", peername, "lastms", str_lastms, NULL); } /*! \brief Automatically add peer extension to dial plan */ @@ -2519,7 +2524,7 @@ int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS); if (ast_test_flag(&global_flags[1], SIP_PAGE2_RTUPDATE) && (ast_test_flag(&p->flags[0], SIP_REALTIME) || rtcachefriends)) { - realtime_update_peer(p->name, &p->addr, p->username, rtcachefriends ? p->fullcontact : NULL, expiry); + realtime_update_peer(p->name, &p->addr, p->username, rtcachefriends ? p->fullcontact : NULL, expiry, p->lastms); } } @@ -8013,9 +8018,10 @@ static void destroy_association(struct sip_peer *peer) { if (!ast_test_flag(&global_flags[1], SIP_PAGE2_IGNOREREGEXPIRE)) { - if (ast_test_flag(&peer->flags[1], SIP_PAGE2_RT_FROMCONTACT)) + if (ast_test_flag(&peer->flags[1], SIP_PAGE2_RT_FROMCONTACT)) { ast_update_realtime("sippeers", "name", peer->name, "fullcontact", "", "ipaddr", "", "port", "", "regseconds", "0", "username", "", "regserver", "", NULL); - else + ast_update_realtime("sippeers", "name", peer->name, "lastms", "", NULL); + } else ast_db_del("SIP/Registry", peer->name); } } @@ -12813,10 +12819,13 @@ peer->call = NULL; if (statechanged) { const char *s = is_reachable ? "Reachable" : "Lagged"; + char lastms_str[20]; ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n", peer->name, s, pingtime, peer->maxms); ast_device_state_changed("SIP/%s", peer->name); + snprintf(lastms_str, sizeof(lastms_str), "%d", pingtime); + ast_update_realtime("sippeers", "name", peer->name, "lastms", lastms_str, NULL); manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: %s\r\nTime: %d\r\n", peer->name, s, pingtime); @@ -16416,6 +16425,7 @@ peer->pokeexpire = -1; if (peer->lastms > -1) { ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Last qualify: %d\n", peer->name, peer->lastms); + ast_update_realtime("sippeers", "name", peer->name, "lastms", "-1", NULL); manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: SIP/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, -1); } if (peer->call) @@ -17275,6 +17285,8 @@ continue; if (realtime && !strcasecmp(v->name, "regseconds")) { ast_get_time_t(v->value, ®seconds, 0, NULL); + } else if (realtime && !strcasecmp(v->name, "lastms")) { + sscanf(v->value, "%d", &peer->lastms); } else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) { inet_aton(v->value, &(peer->addr.sin_addr)); } else if (realtime && !strcasecmp(v->name, "name")) @@ -17482,10 +17494,18 @@ if ((nowtime - regseconds) > 0) { destroy_association(peer); memset(&peer->addr, 0, sizeof(peer->addr)); + peer->lastms = -1; if (option_debug) ast_log(LOG_DEBUG, "Bah, we're expired (%d/%d/%d)!\n", (int)(nowtime - regseconds), (int)regseconds, (int)nowtime); } } + + /* Startup regular pokes */ + if (realtime && peer->lastms > 0) { + ASTOBJ_REF(peer); + sip_poke_peer(peer); + } + ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags); ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags); if (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))