场景

     调用eXosip库跟国标下级进行交互的时候,抓包发现,INVITE请求,前面是添加了jaK.字符串,导致对方解析异常,目前暂时不清楚对方是如何解析的。通过追踪源码,发现是底层做了一个UDP心跳保活的机制,实际上没有这个必要,注释屏蔽掉

jaK.INVITE sip:13010600002000110002@11.11.52.129:5061 SIP/2.0
Via: SIP/2.0/UDP 11.11.54.174:5060;rport;branch=z9hG4bK1153031278
From: <sip:13010600002000110003@11.11.54.174:5060>;tag=364366442
To: <sip:13010600002000110002@11.11.52.129:5061>
Call-ID: 328977807
CSeq: 20 INVITE
Contact: <sip:13010600002000110003@11.11.54.174:5060>
Content-Type: application/sdp
Max-Forwards: 70
User-Agent: eXosip/4.1.0
Subject: 13010462001310110752:0-1,44010000008100000089:1
Supported: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO
Content-Length:   244

v=0
o=13010600002000110003 0 0 IN IP4 11.11.54.174
s=Play
c=IN IP4 11.11.54.174
t=0 0
m=video 36332 TCP/RTP/AVP 96 97 98
a=recvonly
a=setup:active
a=connection:new
a=rtpmap:96 PS/90000
a=rtpmap:97 MPEG4/90000
a=rtpmap:98 H264/90000
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 11.11.54.174:5060;branch=z9hG4bK1153031278;rport=5060
Call-ID: 328977807
From: <sip:13010600002000110003@11.11.54.174:5060>;tag=364366442
To: <sip:13010600002000110002@11.11.52.129:5061>
CSeq: 20 INVITE
Content-Length: 0

SIP/2.0 400 Bad Request
Via: SIP/2.0/UDP 11.11.54.174:5060;branch=z9hG4bK1153031278
Call-ID: 328977807
From: <sip:13010600002000110003@11.11.54.174:5060>;tag=364366442
To: <sip:13010600002000110002@11.11.52.129:5061>;tag=b6f9298b91c94fcda50b7d93d90c7eac-1666774978452
CSeq: 20 INVITE
Max-Forwards: 70
Contact: <sip:13010600002000110002@11.11.52.129:5061>
Content-Length: 0

代码剖析

libeXosip2-4.1.0

src/eXtl_udp.c

static int
udp_tl_keepalive (struct eXosip_t *excontext)
{
  struct eXtludp *reserved = (struct eXtludp *) excontext->eXtludp_reserved;
  char buf[4] = "jaK";
  eXosip_reg_t *jr;

  if (reserved == NULL) {
    OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "wrong state: create transport layer first\n"));
    return OSIP_WRONG_STATE;
  }

  if (excontext->keep_alive <= 0) {
    return 0;
  }

  if (reserved->udp_socket <= 0)
    return OSIP_UNDEFINED_ERROR;

  for (jr = excontext->j_reg; jr != NULL; jr = jr->next) {
    if (jr->len > 0) {
      if (sendto (reserved->udp_socket, (const void *) buf, 4, 0, (struct sockaddr *) &(jr->addr), jr->len) > 0) {
        OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "eXosip: Keep Alive sent on UDP!\n"));
      }
    }
  }
  return OSIP_SUCCESS;
}

libexosip2-5.1.0

src/eXtl_udp.c

通过发送/r/n/r/n实现UDP的心跳保活

    char ka_crlf[5];
  snprintf (excontext->ka_crlf, sizeof (excontext->ka_crlf), "\r\n\r\n");
static int
udp_tl_keepalive (struct eXosip_t *excontext)
{
  struct eXtludp *reserved = (struct eXtludp *) excontext->eXtludp_reserved;
  eXosip_reg_t *jr;

  if (reserved == NULL) {
    OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "wrong state: create transport layer first\n"));
    return OSIP_WRONG_STATE;
  }

  if (excontext->ka_interval <= 0) {
    return 0;
  }

  if (reserved->udp_socket < 0)
    return OSIP_UNDEFINED_ERROR;

  for (jr = excontext->j_reg; jr != NULL; jr = jr->next) {
    if (jr->len > 0) {
      if (sendto (reserved->udp_socket, (const void *) excontext->ka_crlf, 4, 0, (struct sockaddr *) &(jr->addr), jr->len) > 0) {
        OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "eXosip: Keep Alive sent on UDP!\n"));
      }
    }
  }
  return OSIP_SUCCESS;
}
static int
udp_tl_keepalive (struct eXosip_t *excontext)
{
  struct eXtludp *reserved = (struct eXtludp *) excontext->eXtludp_reserved;
  eXosip_reg_t *jr;

  if (reserved == NULL) {
    OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "wrong state: create transport layer first\n"));
    return OSIP_WRONG_STATE;
  }

  if (excontext->ka_interval <= 0) {
    return 0;
  }

  if (reserved->udp_socket < 0)
    return OSIP_UNDEFINED_ERROR;

  for (jr = excontext->j_reg; jr != NULL; jr = jr->next) {
    if (jr->len > 0) {
      if (sendto (reserved->udp_socket, (const void *) excontext->ka_crlf, 4, 0, (struct sockaddr *) &(jr->addr), jr->len) > 0) {
        OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO1, NULL, "eXosip: Keep Alive sent on UDP!\n"));
      }
    }
  }
  return OSIP_SUCCESS;
}

libexosip2-5.3.0

src/eXtl_udp.c

static int udp_tl_keepalive(struct eXosip_t *excontext) {
  struct eXtludp *reserved = (struct eXtludp *) excontext->eXtludp_reserved;
  eXosip_reg_t *jr;

  if (reserved == NULL) {
    OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_ERROR, NULL, "[eXosip] [UDP] wrong state: create transport layer first\n"));
    return OSIP_WRONG_STATE;
  }

  if (excontext->ka_interval <= 0) {
    return 0;
  }

  if (reserved->udp_socket < 0)
    return OSIP_UNDEFINED_ERROR;

  for (jr = excontext->j_reg; jr != NULL; jr = jr->next) {
    if (jr->stun_len > 0) {
      int idx;

      jr->stun_binding.type = htons(0x0001);  // STUN_METHOD_BINDING|STUN_REQUEST
      jr->stun_binding.length = htons(0);
      jr->stun_binding.magic_cookie = htonl(0x2112A442);

      for (idx = 0; idx < 12; idx = idx + 4) {
        /* assert(i+3<16); */
        int r = osip_build_random_number();
        jr->stun_binding.tr_id[idx + 0] = r >> 0;
        jr->stun_binding.tr_id[idx + 1] = r >> 8;
        jr->stun_binding.tr_id[idx + 2] = r >> 16;
        jr->stun_binding.tr_id[idx + 3] = r >> 24;
      }

      if (sendto(reserved->udp_socket, (const void *) &jr->stun_binding, sizeof(jr->stun_binding), 0, (struct sockaddr *) &(jr->stun_addr), jr->stun_len) > 0) {
        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "[eXosip] [UDP] [keepalive] STUN sent on UDP\n"));
        jr->ping_rfc5626 = osip_getsystemtime(NULL) + 9;
      } else {
        char eb[ERRBSIZ];
        OSIP_TRACE(osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "[eXosip] [UDP] [keepalive] failure %s\n", _ex_strerror(ex_errno, eb, ERRBSIZ)));
      }
    }
  }

  return OSIP_SUCCESS;
}

尝试方法

	m_ctx = eXosip_malloc();
	int iRet = eXosip_init(m_ctx);
	m_ctx->ka_interval = 0;//禁用心跳保活
编译提示出错:
使用了未定义类型“eXosip_t”	
“->ka_interval”的左边必须指向类/结构/联合/泛型类型

解决

	m_ctx = eXosip_malloc();
	int iRet = eXosip_init(m_ctx);
	if (iRet != 0)
	{
		return iRet;
	}
	int nKeepAliveInterval = 0;
	eXosip_set_option(m_ctx, EXOSIP_OPT_UDP_KEEP_ALIVE, &nKeepAliveInterval);