Hi!
This week we saw interesing problem with one of our clients: initially he was not able to configure his CCME to register on our proxy, so we just added static location serctl ul add ..., that's our classic workaround for CCME and another not-so-smart admins.
But when he finally configured registration - things gone nuts:
clients asks for registration:
Date: Fri, 24 Oct 2008 13:16:29 GMT Timestamp: 1224854189 CSeq: 2905600 REGISTER Contact: sip:NNNNNNN@AA.BBB.CCC.DD:5060 Expires: 3600 Authorization: Digest ....
and ser replies with 200 OK, but with Contact: field filled with his static registration:
Contact: sip:NNNNNNN@AA.BBB.CCC.DD;q=1;expires=4293498731;received=""
As you can see, expires value is 4293498731, which means that it will be valid for about 136 years, just sixteen days short than 2^32 seconds... So, by RFC, client's router should wait for ~100 years before attempting registration refresh :)
But CCME, i suppose, thinks different, it just adds received expires value to current time, got uint32 overflow and result is now()-16 days. As a result CCME thinks that registration is always expired and tries to re-register immediately... And does so hundredths times per second, creating unnecessary extra load to our proxy and database backend....
Why that is so: modules/registrar/reply.c calculates expires= as
int2str((int)(c->expires - act_time), &len)
but, c->expires can be less than act_time, so, result will be negative integer (translated to unsigned int on call to int2str, and this unsigned int will have higher bit set on, so it will be big one). Well, there are check if(VALID_CONTACT(c, act_time)) which filters out most of the cases where с->expires <= act_time, but for 'static' registrations these checks are off:
((c->expires > act_time) || (c->flags & FL_PERMANENT)) is always true in case of 'static' contact because of FL_PERMANENT.
For now I fixed it with following patch (not perfect, i suppose, it just uses default_expires value for negative expires time, but it was easy to write and it works for me):
--- reply.c.orig Thu Jan 13 11:48:08 2005 +++ reply.c Fri Oct 24 14:08:13 2008 @@ -163,7 +163,11 @@
memcpy(p, EXPIRES_PARAM, EXPIRES_PARAM_LEN); p += EXPIRES_PARAM_LEN; - cp = int2str((int)(c->expires - act_time), &len); + if (c->expires > act_time) { + cp = int2str((int)(c->expires - act_time), &len); + } else { + cp = int2str(default_expires, &len); + } memcpy(p, cp, len); p += len;
Environment: ser-0.9.6/i386/FreeBSD (ser-2.0 has the same code, so it may be affected too). The only tuning of usrloc and registrar modules is db_url and dbmode = 2.