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.