Modify res_pjsip_messaging.c to report status via AMI

I’ve been having issues with devices behind unpredictable network connections not receiving messages. I modified res_pjsip_messaging.c to report status via AMI so I could be sure a message was delivered, or queue it if it wasn’t.

Disclaimer: I’m a raw beginner, so any suggestions would be very much welcome.

static void pjsip_message_response_cb(void *token, pjsip_event *event)
{
  const char *x_message_id = token ? (const char *)token : "";

  if (event->body.tsx_state.src.rdata) {

    pjsip_msg *msg = event->body.tsx_state.src.rdata->msg_info.msg;
    if (msg && msg->type == PJSIP_RESPONSE_MSG) {

      int code = msg->line.status.code;
      const pj_str_t *reason = &msg->line.status.reason;

      char to_buf[256] = "";
      pjsip_hdr *to = pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL);
      if (to) pjsip_hdr_print_on(to, to_buf, sizeof(to_buf)); else pj_ansi_strcpy(to_buf, "To:");

      char from_buf[256] = "";
      pjsip_hdr *from = pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL);
      if (from) pjsip_hdr_print_on(from, from_buf, sizeof(from_buf)); else pj_ansi_strcpy(from_buf, "From:");

      ast_debug(3, "%d %.*s | %s | %s | X-Message-Id: %s\n",
        code, (int)reason->slen, reason->ptr, to_buf, from_buf, x_message_id
      );
      manager_event(EVENT_FLAG_MESSAGE,
        "PJSIPMessageResponse", "ResponseCode: %d\nResponseReason: %.*s\n%s\n%s\nX-Message-Id: %s\n",
         code, (int)reason->slen, reason->ptr, to_buf, from_buf, x_message_id
      );

      ast_free(token);
      return;
    }
  }

  ast_debug(3, "Message with id '%s' timed out.", x_message_id);
  manager_event(EVENT_FLAG_MESSAGE,
    "PJSIPMessageResponse", "ResponseCode: 0\nResponseReason: Timed out\nX-Message-Id: %s\n",
    x_message_id
  );
  ast_free(token);
}

Then a slight modification at the bottom of msg_send:

  /*
   * If the X-Message-Id header has been set, pass it through
   * to the callback function so that we can determine which
   * response is related to which message.
   */
  static const pj_str_t x_message_id = { "X-Message-Id", 12 };
  pjsip_hdr *message_id_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &x_message_id, NULL);
  pjsip_generic_string_hdr *str_message_id_hdr = (pjsip_generic_string_hdr *)message_id_hdr;
  char *token = NULL;
  if (str_message_id_hdr) {
    ast_assert(pj_strlen(&str_message_id_hdr->hvalue) >= str_message_id_hdr->hvalue.slen);
    token = ast_strndup(pj_strbuf(&str_message_id_hdr->hvalue), str_message_id_hdr->hvalue.slen);
    ast_debug(3, "X-Message-Id header found; set token to: %.*s", (int)str_message_id_hdr->hvalue.slen, str_message_id_hdr->hvalue.ptr);
  }

  ast_debug(1, "Sending message to '%s' (via endpoint %s) from '%s'\n",
    uri, ast_sorcery_object_get_id(endpoint), mdata->from);
  if (ast_sip_send_request(tdata, NULL, endpoint, token, pjsip_message_response_cb)) {
    ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n");
    return -1;
  }

Proposed code changes need to be submitted via GitHub, and you need to have signed the contributor agreement.

No problem. I was hoping someone who’s better than “absolute beginner” could take a look over this first so I’ll leave this here for a time and see if anyone can point out improvements.

Minor edits to correct a segfault in niche cases with multiple unreachable contacts.

static void pjsip_message_response_cb(void *token, pjsip_event *event)
{
        ast_debug(4, "Begin the message response callback function.");
        const char *x_message_id = token ? (const char *)token : "";

        if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG
                && event->body.tsx_state.src.rdata
                && event->body.tsx_state.src.rdata->msg_info.msg) {

                pjsip_msg *msg = event->body.tsx_state.src.rdata->msg_info.msg;
                ast_debug(4, "msg set to event->body.tsx_state.src.rdata->msg_info.msg");

                if (msg->type == PJSIP_RESPONSE_MSG) {

                        ast_debug(4, "msg type is PJSIP_RESPONSE_MSG");

                        int code = msg->line.status.code;
                        const pj_str_t *reason = &msg->line.status.reason;

                        char to_buf[256] = "";
                        pjsip_hdr *to = pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL);
                        if (to) pjsip_hdr_print_on(to, to_buf, sizeof(to_buf));
                                else pj_ansi_strcpy(to_buf, "To:");

                        char from_buf[256] = "";
                        pjsip_hdr *from = pjsip_msg_find_hdr(msg, PJSIP_H_FROM, NULL);
                        if (from) pjsip_hdr_print_on(from, from_buf, sizeof(from_buf));
                                else pj_ansi_strcpy(from_buf, "From:");

                        ast_debug(3, "%d %.*s | %s | %s | X-Message-Id: %s\n",
                                code, (int)reason->slen, reason->ptr, to_buf, from_buf, x_message_id
                        );
                        manager_event(EVENT_FLAG_MESSAGE,
                                "PJSIPMessageResponse",
                                "ResponseCode: %d\nResponseReason: %.*s\n%s\n%s\nX-Message-Id: %s\n",
                                code, (int)reason->slen, reason->ptr, to_buf, from_buf, x_message_id
                        );

                        ast_free(token);
                        return;
                }
        }

        ast_debug(3, "Message with id '%s' timed out.", x_message_id);
        manager_event(EVENT_FLAG_MESSAGE,
                "PJSIPMessageResponse",
                "ResponseCode: 0\nResponseReason: Timed out\nX-Message-Id: %s\n",
                x_message_id
        );
        ast_free(token);
}
1 Like

That is going to be done by more advanced programmers ONLY IF you do as you were instructed and file a github ticket.

This is to protect Asterisk. The moment you post code here, in the forum, legally it has your copyright on it. That’s just how copyright works. So if ANY developer comments on it - or even a non-developer like me - and perhaps makes the fix you suggest in the Asterisk source code - then you could conceivably file a copyright infringement against the project. Now, sure, you would be EXTREMELY unlikely to prevail in a court case - but the Project has no interest in experimenting. Unlike many FOSS projects, the sponsor of Asterisk has deeper pockets than just some dude operating in his free time.

This is why there is a strong policy on the development team to NOT pay attention to requests to review code - even trivial patches. And honestly, by you NOT doing as directed and filing the patch in github - it will DELAY implementing it in the code.

Please do as directed and open the appropriate ticket in github. Thanks!

Oh, interesting. Thank you for the explanation; I appreciate it.

I’m not concerned about a delay - maybe this is too niche to even be useful to anyone else anyway - but I will submit it.