[pjsip] Parsing expires from REGISTER reply

Alan J. Bond alan.bond at wintology.com
Sat May 3 18:51:09 EDT 2008


Hi, I'm very new to PJSIP (2 days only).  So far I've managed to build everything under VS2008 and run test_pjsip successfully.  I've now moved on to fooling with the simple_pjsua sample.



I am using it against a system from PortaOne<www.portaone.com>, which comprises various bits of open source running on FreeBSD.  The SIP server appears to be based on an early release of SER, complete with the problem described in this post from Benny in the PJSIP list archive:



      http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-April/002633.html



Here is the REGISTER 200 reply showing the same 'corrupted' Contact: header and no separate Expires: header.  The expires=3595 is not being parsed/returned so pjsua_acc.c thinks it's 0 and therefore an unregistration.  No re-registration therefore ever takes place.



SIP/2.0 200 OK

Via: SIP/2.0/UDP 192.168.128.10:5061;rport=5061;branch=z9hG4bKPj8d40d41940df4d20b03703147ef286f5;received=81.xxx.xxx.xxx

From: <sip:510xxx5841 at sip.xxx.xxx>;tag=474ba5bb6ad0407092ea709d5aa0f5d4

To: <sip:510xxx5841 at sip.xxx.xxx>;tag=4c9d2783942a2e60e4b45662ff0ad8ea-400a

Call-ID: 2868b060ba464f73bae210216a307dd2

CSeq: 18510 REGISTER

PortaBilling: available-funds:9.71 currency:GBP

Contact: <sip:510xxx5841 at 81.xxx.xxx.xxx:5061;transport=UDP>;expires=3595

Server: Sip EXpress router (0.9.6 (i386/freebsd))

Content-Length: 0



--end msg--

 20:07:03.383    tsx0209C12C Incoming Response msg 200/REGISTER/cseq=18510 (rdata0206A254) in state Calling

 20:07:03.383    tsx0209C12C State changed from Calling to Completed, event=RX_MSG

 20:07:03.383    pjsua_acc.c sip:510xxx5841 at sip.xxx.xxx: unregistration success





When I look at the "Contact:" header parsing in sip_parser.c I see what appears to be code to parse the trailing "expires=":


/* Parse and interpret Contact param. */
static void int_parse_contact_param( pjsip_contact_hdr *hdr,
                             pj_scanner *scanner,
                             pj_pool_t *pool)
{
    while ( *scanner->curptr == ';' ) {
      pj_str_t pname, pvalue;

      int_parse_param( scanner, pool, &pname, &pvalue, 0);
      if (!parser_stricmp(pname, pconst.pjsip_Q_STR) && pvalue.slen) {
          char *dot_pos = (char*) pj_memchr(pvalue.ptr, '.', pvalue.slen);
          if (!dot_pos) {
            hdr->q1000 = pj_strtoul(&pvalue);
          } else {
            pvalue.slen = (pvalue.ptr+pvalue.slen) - (dot_pos+1);
            pvalue.ptr = dot_pos + 1;
            hdr->q1000 = pj_strtoul_mindigit(&pvalue, 3);
          }
      } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) && pvalue.slen) {
          hdr->expires = pj_strtoul(&pvalue);

      } else {
          pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
          p->name = pname;
          p->value = pvalue;
          pj_list_insert_before(&hdr->other_param, p);
      }
    }
}

/* Parse Contact header. */
static pjsip_hdr* parse_hdr_contact( pjsip_parse_ctx *ctx )
{
    pjsip_contact_hdr *first = NULL;
    pj_scanner *scanner = ctx->scanner;

    do {
      pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(ctx->pool);
      if (first == NULL)
          first = hdr;
      else
          pj_list_insert_before(first, hdr);

      if (*scanner->curptr == '*') {
          pj_scan_get_char(scanner);
          hdr->star = 1;

      } else {
          hdr->star = 0;
          hdr->uri = int_parse_uri_or_name_addr(scanner, ctx->pool,
                                                  PJSIP_PARSE_URI_AS_NAMEADDR |
                                      PJSIP_PARSE_URI_IN_FROM_TO_HDR);

          int_parse_contact_param(hdr, scanner, ctx->pool);
      }

      if (*scanner->curptr != ',')
          break;

      pj_scan_get_char(scanner);

    } while (1);

    parse_hdr_end(scanner);

    return (pjsip_hdr*)first;
}



Eventually 0 seems to be passed to this handler in pjsua_acc.c which produces the last message in the log above ...


/*
 * This callback is called by pjsip_regc when outgoing register
 * request has completed.
 */
static void regc_cb(struct pjsip_regc_cbparam *param)
{

    pjsua_acc *acc = (pjsua_acc*) param->token;

    if (param->regc != acc->regc)
      return;

    PJSUA_LOCK();

    /*
     * Print registration status.
     */
    if (param->status!=PJ_SUCCESS) {
      pjsua_perror(THIS_FILE, "SIP registration error",
                 param->status);
      pjsip_regc_destroy(acc->regc);
      acc->regc = NULL;

      /* Stop keep-alive timer if any. */
      update_keep_alive(acc, PJ_FALSE, NULL);

    } else if (param->code < 0 || param->code >= 300) {
      PJ_LOG(2, (THIS_FILE, "SIP registration failed, status=%d (%.*s)",
               param->code,
               (int)param->reason.slen, param->reason.ptr));
      pjsip_regc_destroy(acc->regc);
      acc->regc = NULL;

      /* Stop keep-alive timer if any. */
      update_keep_alive(acc, PJ_FALSE, NULL);

    } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {

      if (param->expiration < 1) {
          pjsip_regc_destroy(acc->regc);
          acc->regc = NULL;

          /* Stop keep-alive timer if any. */
          update_keep_alive(acc, PJ_FALSE, NULL);

          PJ_LOG(3,(THIS_FILE, "%s: unregistration success",
                  pjsua_var.acc[acc->index].cfg.id.ptr));
      } else {
          /* Check NAT bound address */
          if (acc_check_nat_addr(acc, param)) {
            /* Update address, don't notify application yet */
            PJSUA_UNLOCK();
            return;
          }

          /* Check and update Service-Route header */
          update_service_route(acc, param->rdata);

          PJ_LOG(3, (THIS_FILE,
                   "%s: registration success, status=%d (%.*s), "
                   "will re-register in %d seconds",
                   pjsua_var.acc[acc->index].cfg.id.ptr,
                   param->code,
                   (int)param->reason.slen, param->reason.ptr,
                   param->expiration));

          /* Start keep-alive timer if necessary. */
          update_keep_alive(acc, PJ_TRUE, param);

          /* Send initial PUBLISH if it is enabled */
          if (acc->cfg.publish_enabled && acc->publish_sess==NULL)
            pjsua_pres_init_publish_acc(acc->index);
      }

    } else {
      PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));
    }

    acc->reg_last_err = param->status;
    acc->reg_last_code = param->code;

    if (pjsua_var.ua_cfg.cb.on_reg_state)
      (*pjsua_var.ua_cfg.cb.on_reg_state)(acc->index);

    PJSUA_UNLOCK();
}



I haven't had time to run up a debug version of the whole thing yet to single step through this and establish exactly what is going on here and therefore have no idea what goes on between the parsing and the handler being called.  I do note, however, that the parsing code is ostensibly putting the expiry time in a pjsip_contact_hdr structure.  Maybe this is being discarded on route to the handler.



Can anyone more familiar with this code throw any light on this?  Whatever we may think of SER with regard to the RFCs it is a widely used implementation (even ones this old) and PJSIP ought to handle this.



Best Regards,

Alan.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/attachments/20080503/562025d2/attachment.html>


More information about the pjsip mailing list