--- chan_sip.c.bak 2006-04-15 12:41:34.000000000 +0900 +++ chan_sip.c 2006-04-22 12:42:07.000000000 +0900 @@ -690,6 +690,8 @@ struct ast_variable *chanvars; /*!< Channel variables to set for call */ struct sip_pvt *next; /*!< Next call in chain */ struct sip_invite_param *options; /*!< Options for INVITE */ + int sip_reinvite_timer; /*!< SE timer id s.nakamura (i assume to initialized by zero...) */ + int timer_se; /*!< SE timer value s.nakamura */ } *iflist = NULL; #define FLAG_RESPONSE (1 << 0) @@ -792,6 +794,7 @@ struct sockaddr_in defaddr; /*!< Default IP address, used until registration */ struct ast_ha *ha; /*!< Access control list */ struct ast_variable *chanvars; /*!< Variables to set for channel created by user */ + int session_expires; /*!< Session-expires (SE timer) value s.nakamura */ int lastmsg; }; @@ -1763,6 +1766,18 @@ return p; } +/*! \brief find_peer_by_username: Locate peer by username + * s.nakamura */ +static struct sip_peer *find_peer_by_username(const char *peer) +{ + struct sip_peer *p = NULL; + ASTOBJ_CONTAINER_TRAVERSE(&peerl, !p, do { + if (!(strcasecmp(iterator->username, peer))) + p = ASTOBJ_REF(iterator); + } while (0)); + return p; +} + /*! \brief sip_destroy_user: Remove user object from in-memory storage ---*/ static void sip_destroy_user(struct sip_user *user) { @@ -4583,6 +4598,15 @@ return 1; } +/*! \brief sip_session_timeout: SE timer + * s.nakamura */ +static int sip_session_timeout(void *data) +{ + struct sip_pvt *p = (struct sip_pvt *) data; + p->sip_reinvite_timer = 0; + return transmit_reinvite_with_sdp(p); +} + /*! \brief transmit_reinvite_with_sdp: Transmit reinvite with SDP :-) ---*/ /* A re-invite is basically a new INVITE with the same CALL-ID and TAG as the INVITE that opened the SIP dialogue @@ -4596,6 +4620,15 @@ reqprep(&req, p, SIP_UPDATE, 0, 1); else reqprep(&req, p, SIP_INVITE, 0, 1); + + /* if necessary, add se-timer headers ... s.nakamura */ + if (p->timer_se > 0) { + char expstr[64]; + memset(expstr, 0, sizeof(expstr)); + snprintf(expstr, sizeof(expstr), "%d;refresher=uac", p->timer_se); + add_header(&req, "Session-Expires", expstr); + add_header(&req, "Supported", "timer"); + } add_header(&req, "Allow", ALLOWED_METHODS); if (sipdebug) @@ -4887,6 +4920,18 @@ if (!ast_strlen_zero(p->referred_by)) add_header(&req, "Referred-By", p->referred_by); } + /* add se-timer headers when "session-expires" is specified in sip.conf ... s.nakamura */ + char expstr[64]; + struct sip_peer *peer = NULL; + peer = find_peer_by_username(p->peername); + if (peer != NULL && peer->session_expires > 0) { + memset(expstr, 0, sizeof(expstr)); + snprintf(expstr, sizeof(expstr), "%d;refresher=uac", peer->session_expires); + p->sip_reinvite_timer = 0; + p->timer_se = peer->session_expires; + add_header(&req, "Session-Expires", expstr); + add_header(&req, "Supported", "timer"); + } #ifdef OSP_SUPPORT if ((req.method != SIP_OPTIONS) && p->options && !ast_strlen_zero(p->options->osptoken)) { ast_log(LOG_DEBUG,"Adding OSP Token: %s\n", p->options->osptoken); @@ -5582,6 +5627,10 @@ /*! \brief transmit_request: transmit generic SIP request ---*/ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, int reliable, int newbranch) { + /* remove se-timer callback ... s.nakamura */ + if (sipmethod == SIP_BYE && p->sip_reinvite_timer != 0) { + ast_sched_del(sched, p->sip_reinvite_timer); + } struct sip_request resp; reqprep(&resp, p, sipmethod, seqno, newbranch); add_header_contentLength(&resp, 0); @@ -5592,6 +5641,11 @@ /*! \brief transmit_request_with_auth: Transmit SIP request, auth added ---*/ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, int reliable, int newbranch) { + /* remove se-timer callback ... s.nakamura */ + if (sipmethod == SIP_BYE && p->sip_reinvite_timer != 0) { + ast_sched_del(sched, p->sip_reinvite_timer); + } + struct sip_request resp; reqprep(&resp, p, sipmethod, seqno, newbranch); @@ -9530,6 +9584,18 @@ /* If I understand this right, the branch is different for a non-200 ACK only */ transmit_request(p, SIP_ACK, seqno, 0, 1); check_pendings(p); + + /* add se-timer callback ... s.nakamura */ + char *ph = get_header(req, "x"); + char *pr = strstr(ph, ";refresher=uac"); + char timestr[16]; + if (pr) { + memset(timestr, 0, sizeof(timestr)); + strncpy(timestr, ph, pr-ph); + sscanf(timestr, "%d", &(p->timer_se)); + if (p->timer_se > 0) + p->sip_reinvite_timer = ast_sched_add(sched, p->timer_se / 2 * 1000, sip_session_timeout, p); + } break; case 407: /* Proxy authentication */ case 401: /* Www auth */ @@ -10611,6 +10677,11 @@ int res; struct ast_channel *bridged_to; char iabuf[INET_ADDRSTRLEN]; + + /* remove se timer callback ... s.nakamura */ + if (p->sip_reinvite_timer != 0) { + ast_sched_del(sched, p->sip_reinvite_timer); + } if (p->pendinginvite && !ast_test_flag(p, SIP_OUTGOING) && !ignore) transmit_response_reliable(p, "487 Request Terminated", &p->initreq, 1); @@ -12268,6 +12339,13 @@ /* else if (strcasecmp(v->name,"type")) * ast_log(LOG_WARNING, "Ignoring %s\n", v->name); */ + /* add session-expires (se timer value) ... s.nakamura */ + else if (!strcasecmp(v->name, "session-expires")) { + if ((sscanf(v->value, "%d", &peer->session_expires) !=1) || (peer->session_expires < 0)) { + ast_log(LOG_WARNING, "'%s' is not a valid Session-Expires time value at line %d. Using default.\n", v->value, v->lineno); + peer->session_expires = 0; + } + } v=v->next; } if (!ast_test_flag((&global_flags_page2), SIP_PAGE2_IGNOREREGEXPIRE) && ast_test_flag(peer, SIP_DYNAMIC) && realtime) {