Esempio n. 1
0
static int print_media_desc( pjmedia_sdp_media *m, char *buf, int len)
{
    char *p = buf;
    char *end = buf+len;
    unsigned i;
    int printed;

    /* check length for the "m=" line. */
    if (len < m->desc.media.slen+m->desc.transport.slen+12+24) {
	return -1;
    }
    *p++ = 'm';	    /* m= */
    *p++ = '=';
    pj_memcpy(p, m->desc.media.ptr, m->desc.media.slen);
    p += m->desc.media.slen;
    *p++ = ' ';
    printed = pj_utoa(m->desc.port, p);
    p += printed;
    if (m->desc.port_count > 1) {
	*p++ = '/';
	printed = pj_utoa(m->desc.port_count, p);
	p += printed;
    }
    *p++ = ' ';
    pj_memcpy(p, m->desc.transport.ptr, m->desc.transport.slen);
    p += m->desc.transport.slen;
    for (i=0; i<m->desc.fmt_count; ++i) {
	*p++ = ' ';
	pj_memcpy(p, m->desc.fmt[i].ptr, m->desc.fmt[i].slen);
	p += m->desc.fmt[i].slen;
    }
    *p++ = '\r';
    *p++ = '\n';

    /* print connection info, if present. */
    if (m->conn) {
	printed = print_connection_info(m->conn, p, end-p);
	if (printed < 0) {
	    return -1;
	}
	p += printed;
    }

    /* print attributes. */
    for (i=0; i<m->attr_count; ++i) {
	printed = print_attr(m->attr[i], p, end-p);
	if (printed < 0) {
	    return -1;
	}
	p += printed;
    }

    return p-buf;
}
Esempio n. 2
0
/*
 * Min-SE header vptr.
 */
static int min_se_hdr_print(pjsip_min_se_hdr *hdr, 
			    char *buf, pj_size_t size)
{
    char *p = buf;
    char *endbuf = buf+size;
    pj_ssize_t printed;
    const pjsip_parser_const_t *pc = pjsip_parser_const();

    /* Print header name and value */
    if ((endbuf - p) < (hdr->name.slen + 16))
	return -1;

    copy_advance(p, hdr->name);
    *p++ = ':';
    *p++ = ' ';

    printed = pj_utoa(hdr->min_se, p);
    p += printed;

    /* Print generic params */
    printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
				   &pc->pjsip_TOKEN_SPEC, 
				   &pc->pjsip_TOKEN_SPEC, ';');
    if (printed < 0)
	return (int)printed;

    p += printed;
    return (int)(p - buf);
}
Esempio n. 3
0
/**
 * Apply opus settings to dec_fmtp parameters
 */
void apply_opus_codec_params(pj_pool_t *pool, pjmedia_codec_param *attr) {
  attr->setting.dec_fmtp.cnt = 0;
  if (attr->setting.plc == 0) {
    attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name =
        pj_str("useinbandfec");
    attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val = pj_str("0");
    attr->setting.dec_fmtp.cnt++;
  }
  if (attr->setting.vad == 1) {
    attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name =
        pj_str("usedtx");
    attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val = pj_str("1");
    attr->setting.dec_fmtp.cnt++;
  }
  if (attr->info.channel_cnt == 2) {
    attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name =
        pj_str("stereo");
    attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val = pj_str("1");
    attr->setting.dec_fmtp.cnt++;
  }
  if (attr->info.clock_rate < 48000) {
    attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].name =
        pj_str("maxplaybackrate");
    char clock_rate_char[8];
    pj_utoa(attr->info.clock_rate, clock_rate_char);
    pj_strdup2(pool,
               &attr->setting.dec_fmtp.param[attr->setting.dec_fmtp.cnt].val,
               clock_rate_char);
    attr->setting.dec_fmtp.cnt++;
  }
}
Esempio n. 4
0
void SIPPresence::updateStatus(bool status, const std::string &note)
{
    //char* pj_note  = (char*) pj_pool_alloc(pool_, "50");

    pjrpid_element rpid = {
        PJRPID_ELEMENT_TYPE_PERSON,
        CONST_PJ_STR("0"),
        PJRPID_ACTIVITY_UNKNOWN,
        pj_str((char *) note.c_str())
    };

    /* fill activity if user not available. */
    if (note == "away")
        rpid.activity = PJRPID_ACTIVITY_AWAY;
    else if (note == "busy")
        rpid.activity = PJRPID_ACTIVITY_BUSY;
    /*
    else // TODO: is there any other possibilities
        DEBUG("Presence : no activity");
    */

    pj_bzero(&status_data_, sizeof(status_data_));
    status_data_.info_cnt = 1;
    status_data_.info[0].basic_open = status;

    // at most we will have 3 digits + NULL termination
    char buf[4];
    pj_utoa(rand() % 1000, buf);
    status_data_.info[0].id = pj_strdup3(pool_, buf);

    pj_memcpy(&status_data_.info[0].rpid, &rpid, sizeof(pjrpid_element));
    /* "contact" field is optionnal */
}
PJ_DEF(pj_xml_node*) pjsip_iscomposing_create_xml( pj_pool_t *pool,
						   pj_bool_t is_composing,
						   const pj_time_val *lst_actv,
						   const pj_str_t *content_tp,
						   int refresh)
{
    pj_xml_node *doc, *node;
    pj_xml_attr *attr;

    /* Root document. */
    doc = pj_xml_node_new(pool, &STR_ISCOMPOSING);

    /* Add attributes */
    attr = pj_xml_attr_new(pool, &STR_XMLNS_NAME, &STR_XMLNS_VAL);
    pj_xml_add_attr(doc, attr);

    attr = pj_xml_attr_new(pool, &STR_XMLNS_XSI_NAME, &STR_XMLNS_XSI_VAL);
    pj_xml_add_attr(doc, attr);

    attr = pj_xml_attr_new(pool, &STR_XSI_SLOC_NAME, &STR_XSI_SLOC_VAL);
    pj_xml_add_attr(doc, attr);


    /* Add state. */
    node = pj_xml_node_new(pool, &STR_STATE);
    if (is_composing)
	node->content = STR_ACTIVE;
    else
	node->content = STR_IDLE;
    pj_xml_add_node(doc, node);

    /* Add lastactive, if any. */
    PJ_UNUSED_ARG(lst_actv);
    //if (!is_composing && lst_actv) {
    //	PJ_TODO(IMPLEMENT_LAST_ACTIVE_ATTRIBUTE);
    //}

    /* Add contenttype, if any. */
    if (content_tp) {
	node = pj_xml_node_new(pool, &STR_CONTENTTYPE);
	pj_strdup(pool, &node->content, content_tp);
	pj_xml_add_node(doc, node);
    }

    /* Add refresh, if any. */
    if (is_composing && refresh > 1 && refresh < 3601) {
	node = pj_xml_node_new(pool, &STR_REFRESH);
	node->content.ptr = (char*) pj_pool_alloc(pool, 10);
	node->content.slen = pj_utoa(refresh, node->content.ptr);
	pj_xml_add_node(doc, node);
    }

    /* Done! */

    return doc;
}
Esempio n. 6
0
int pjsip_session_expires_hdr_print_on(void* h, char* buf, pj_size_t len)
{
  char* p = buf;
  const pjsip_session_expires_hdr* hdr = (pjsip_session_expires_hdr*)h;
  const pjsip_parser_const_t *pc = pjsip_parser_const();

  // As per pjsip_generic_int_hdr_print, integers are fewer then 15 characters long.
  if ((pj_ssize_t)len < hdr->name.slen + 15)
  {
    return -1;
  }

  pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
  p += hdr->name.slen;
  *p++ = ':';
  *p++ = ' ';
  p += pj_utoa(hdr->expires, p);

  if (hdr->refresher != SESSION_REFRESHER_UNKNOWN)
  {
    // Check the refresher parameter will fit.
    if (buf+len-p < 14)
    {
      return -1;
    }

    // Fill it in
    *p++ = ';';
    pj_memcpy(p, "refresher=", 10);
    p += 10;

    if (hdr->refresher == SESSION_REFRESHER_UAC)
    {
      pj_memcpy(p, "uac", 3);
    }
    else
    {
      pj_memcpy(p, "uas", 3);
    }
    p += 3;
  }

  // Try to add the other params.
  pj_ssize_t printed = pjsip_param_print_on(&hdr->other_param, p, buf+len-p,
                                            &pc->pjsip_TOKEN_SPEC,
                                            &pc->pjsip_TOKEN_SPEC, ';');
  if (printed < 0)
  {
    return -1;
  }
  p += printed;
  *p = '\0';

  return p - buf;
}
Esempio n. 7
0
static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, 
				     char *buf, pj_size_t size)
{
    char *p = buf;
    char *endbuf = buf+size;
    pj_ssize_t printed;
    const pjsip_parser_const_t *pc = pjsip_parser_const();

    copy_advance(p, hdr->name);
    *p++ = ':';
    *p++ = ' ';

    copy_advance_escape(p, hdr->sub_state, pc->pjsip_TOKEN_SPEC);
    copy_advance_pair_escape(p, ";reason=", 8, hdr->reason_param,
			     pc->pjsip_TOKEN_SPEC);
    if (hdr->expires_param >= 0) {
	pj_memcpy(p, ";expires=", 9);
	p += 9;
	printed = pj_utoa(hdr->expires_param, p);
	p += printed;
    }
    if (hdr->retry_after >= 0) {
	pj_memcpy(p, ";retry-after=", 13);
	p += 13;
	printed = pj_utoa(hdr->retry_after, p);
	p += printed;
    }
    
    printed = pjsip_param_print_on( &hdr->other_param, p, endbuf-p, 
				    &pc->pjsip_TOKEN_SPEC,
				    &pc->pjsip_TOKEN_SPEC,
				    ';');
    if (printed < 0)
	return (int)printed;

    p += printed;

    return (int)(p - buf);
}
Esempio n. 8
0
static pj_ssize_t print_bandw(const pjmedia_sdp_bandw *bandw,
			      char *buf, pj_size_t len)
{
    char *p = buf;

    if ((int)len < bandw->modifier.slen + 10 + 5)
	return -1;

    *p++ = 'b';
    *p++ = '=';
    pj_memcpy(p, bandw->modifier.ptr, bandw->modifier.slen);
    p += bandw->modifier.slen;
    *p++ = ':';
    p += pj_utoa(bandw->value, p);

    *p++ = '\r';
    *p++ = '\n';
    return p-buf;
}
Esempio n. 9
0
/*
 * Session-Expires header vptr.
 */
static int se_hdr_print(pjsip_sess_expires_hdr *hdr, 
			char *buf, pj_size_t size)
{
    char *p = buf;
    char *endbuf = buf+size;
    pj_ssize_t printed;
    const pjsip_parser_const_t *pc = pjsip_parser_const();
    const pj_str_t *hname = pjsip_use_compact_form? &hdr->sname : &hdr->name;

    /* Print header name and value */
    if ((endbuf - p) < (hname->slen + 16))
	return -1;

    copy_advance(p, (*hname));
    *p++ = ':';
    *p++ = ' ';

    printed = pj_utoa(hdr->sess_expires, p);
    p += printed;

    /* Print 'refresher' param */
    if (hdr->refresher.slen)
    {
	if  ((endbuf - p) < (STR_REFRESHER.slen + 2 + hdr->refresher.slen))
	    return -1;

	*p++ = ';';
	copy_advance(p, STR_REFRESHER);
	*p++ = '=';
	copy_advance(p, hdr->refresher);
    }

    /* Print generic params */
    printed = pjsip_param_print_on(&hdr->other_param, p, endbuf-p,
				   &pc->pjsip_TOKEN_SPEC, 
				   &pc->pjsip_TOKEN_SPEC, ';');
    if (printed < 0)
	return (int)printed;

    p += printed;
    return (int)(p - buf);
}
Esempio n. 10
0
static int print_session(const pjmedia_sdp_session *ses, 
			 char *buf, pj_ssize_t len)
{
    char *p = buf;
    char *end = buf+len;
    unsigned i;
    int printed;

    /* Check length for v= and o= lines. */
    if (len < 5+ 
	      2+ses->origin.user.slen+18+
	      ses->origin.net_type.slen+ses->origin.addr.slen + 2)
    {
	return -1;
    }

    /* SDP version (v= line) */
    pj_memcpy(p, "v=0\r\n", 5);
    p += 5;

    /* Owner (o=) line. */
    *p++ = 'o';
    *p++ = '=';
    pj_memcpy(p, ses->origin.user.ptr, ses->origin.user.slen);
    p += ses->origin.user.slen;
    *p++ = ' ';
    printed = pj_utoa(ses->origin.id, p);
    p += printed;
    *p++ = ' ';
    printed = pj_utoa(ses->origin.version, p);
    p += printed;
    *p++ = ' ';
    pj_memcpy(p, ses->origin.net_type.ptr, ses->origin.net_type.slen);
    p += ses->origin.net_type.slen;
    *p++ = ' ';
    pj_memcpy(p, ses->origin.addr_type.ptr, ses->origin.addr_type.slen);
    p += ses->origin.addr_type.slen;
    *p++ = ' ';
    pj_memcpy(p, ses->origin.addr.ptr, ses->origin.addr.slen);
    p += ses->origin.addr.slen;
    *p++ = '\r';
    *p++ = '\n';

    /* Session name (s=) line. */
    if ((end-p)  < 8+ses->name.slen) {
	return -1;
    }
    *p++ = 's';
    *p++ = '=';
    pj_memcpy(p, ses->name.ptr, ses->name.slen);
    p += ses->name.slen;
    *p++ = '\r';
    *p++ = '\n';

    /* Connection line (c=) if exist. */
    if (ses->conn) {
	printed = print_connection_info(ses->conn, p, end-p);
	if (printed < 1) {
	    return -1;
	}
	p += printed;
    }


    /* Time */
    if ((end-p) < 24) {
	return -1;
    }
    *p++ = 't';
    *p++ = '=';
    printed = pj_utoa(ses->time.start, p);
    p += printed;
    *p++ = ' ';
    printed = pj_utoa(ses->time.stop, p);
    p += printed;
    *p++ = '\r';
    *p++ = '\n';

    /* Print all attribute (a=) lines. */
    for (i=0; i<ses->attr_count; ++i) {
	printed = print_attr(ses->attr[i], p, end-p);
	if (printed < 0) {
	    return -1;
	}
	p += printed;
    }

    /* Print media (m=) lines. */
    for (i=0; i<ses->media_count; ++i) {
	printed = print_media_desc(ses->media[i], p, end-p);
	if (printed < 0) {
	    return -1;
	}
	p += printed;
    }

    return p-buf;
}
Esempio n. 11
0
static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
                                    const pjsip_sip_uri *url,
                                    char *buf, pj_size_t size)
{
    int printed;
    char *startbuf = buf;
    char *endbuf = buf+size;
    const pj_str_t *scheme;

    *buf = '\0';

    /* Print scheme ("sip:" or "sips:") */
    scheme = pjsip_uri_get_scheme(url);
    copy_advance_check(buf, *scheme);
    *buf++ = ':';

    /* Print "user:password@", if any. */
    if (url->user.slen) {
        copy_advance_escape(buf, url->user, pjsip_USER_SPEC);
        if (url->passwd.slen) {
            *buf++ = ':';
            copy_advance_escape(buf, url->passwd, pjsip_PASSWD_SPEC);
        }

        *buf++ = '@';
    }

    /* Print host. */
    pj_assert(url->host.slen != 0);
    copy_advance_check(buf, url->host);

    /* Only print port if it is explicitly specified.
     * Port is not allowed in To and From header.
     */
    /* Unfortunately some UA requires us to send back the port
     * number exactly as it was sent. We don't remember whether an
     * UA has sent us port, so we'll just send the port indiscrimately
     */
    //PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER)
    if (url->port && context != PJSIP_URI_IN_FROMTO_HDR) {
        if (endbuf - buf < 10)
            return -1;

        *buf++ = ':';
        printed = pj_utoa(url->port, buf);
        buf += printed;
    }

    /* User param is allowed in all contexes */
    copy_advance_pair_check(buf, ";user="******";method=", 8, url->method_param,
                                 pjsip_PARAM_CHAR_SPEC);
    }

    /* Transport is not allowed in From/To header. */
    if (context != PJSIP_URI_IN_FROMTO_HDR) {
        copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param,
                                 pjsip_PARAM_CHAR_SPEC);
    }

    /* TTL param is not allowed in From, To, Route, and Record-Route header. */
    if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
            context != PJSIP_URI_IN_ROUTING_HDR)
    {
        if (endbuf - buf < 15)
            return -1;
        pj_memcpy(buf, ";ttl=", 5);
        printed = pj_utoa(url->ttl_param, buf+5);
        buf += printed + 5;
    }

    /* maddr param is not allowed in From and To header. */
    if (context != PJSIP_URI_IN_FROMTO_HDR) {
        copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param,
                                 pjsip_PARAM_CHAR_SPEC);
    }

    /* lr param is not allowed in From, To, and Contact header. */
    if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&
            context != PJSIP_URI_IN_CONTACT_HDR)
    {
        pj_str_t lr = { ";lr", 3 };
        if (endbuf - buf < 3)
            return -1;
        copy_advance_check(buf, lr);
    }

    /* Other param. */
    printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf,
                                   &pjsip_PARAM_CHAR_SPEC,
                                   &pjsip_PARAM_CHAR_SPEC, ';');
    if (printed < 0)
        return -1;
    buf += printed;

    /* Header param.
     * Header param is only allowed in these contexts:
     *	- PJSIP_URI_IN_CONTACT_HDR
     *	- PJSIP_URI_IN_OTHER
     */
    if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) {
        printed = pjsip_param_print_on(&url->header_param, buf, endbuf-buf,
                                       &pjsip_HDR_CHAR_SPEC,
                                       &pjsip_HDR_CHAR_SPEC, '?');
        if (printed < 0)
            return -1;
        buf += printed;
    }

    *buf = '\0';
    return buf-startbuf;
}
Esempio n. 12
0
/**
 * Create a SDP session description that describes the endpoint
 * capability.
 */
PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
					      pj_pool_t *pool,
					      unsigned stream_cnt,
					      const pjmedia_sock_info sock_info[],
					      pjmedia_sdp_session **p_sdp )
{
    pj_time_val tv;
    unsigned i;
    pjmedia_sdp_session *sdp;
    pjmedia_sdp_media *m;
    pjmedia_sdp_attr *attr;

    /* Sanity check arguments */
    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);

    /* Check that there are not too many codecs */
    PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
		     PJ_ETOOMANY);

    /* Create and initialize basic SDP session */
    sdp = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_session));

    pj_gettimeofday(&tv);
    sdp->origin.user = pj_str("-");
    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
    sdp->origin.net_type = STR_IN;
    sdp->origin.addr_type = STR_IP4;
    pj_strdup2(pool, &sdp->origin.addr, 
	       pj_inet_ntoa(sock_info[0].rtp_addr_name.sin_addr));
    sdp->name = STR_SDP_NAME;

    /* Since we only support one media stream at present, put the
     * SDP connection line in the session level.
     */
    sdp->conn = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_conn));
    sdp->conn->net_type = STR_IN;
    sdp->conn->addr_type = STR_IP4;
    pj_strdup2(pool, &sdp->conn->addr, 
	       pj_inet_ntoa(sock_info[0].rtp_addr_name.sin_addr));


    /* SDP time and attributes. */
    sdp->time.start = sdp->time.stop = 0;
    sdp->attr_count = 0;

    /* Create media stream 0: */

    sdp->media_count = 1;
    m = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_media));
    sdp->media[0] = m;

    /* Standard media info: */
    pj_strdup(pool, &m->desc.media, &STR_AUDIO);
    m->desc.port = pj_ntohs(sock_info[0].rtp_addr_name.sin_port);
    m->desc.port_count = 1;
    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);

    /* Init media line and attribute list. */
    m->desc.fmt_count = 0;
    m->attr_count = 0;

    /* Add "rtcp" attribute */
#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
    {
	attr = pj_pool_alloc(pool, sizeof(pjmedia_sdp_attr));
	attr->name = pj_str("rtcp");
	attr->value.ptr = pj_pool_alloc(pool, 80);
	attr->value.slen = 
	    pj_ansi_snprintf(attr->value.ptr, 80,
			    "%u IN IP4 %s",
			    pj_ntohs(sock_info[0].rtcp_addr_name.sin_port),
			    pj_inet_ntoa(sock_info[0].rtcp_addr_name.sin_addr));
	pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
    }
#endif

    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
    for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {

	pjmedia_codec_info *codec_info;
	pjmedia_sdp_rtpmap rtpmap;
	char tmp_param[3];
	pjmedia_sdp_attr *attr;
	pjmedia_codec_param codec_param;
	pj_str_t *fmt;

	if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
	    break;

	codec_info = &endpt->codec_mgr.codec_desc[i].info;
	pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
					    &codec_param);
	fmt = &m->desc.fmt[m->desc.fmt_count++];

	fmt->ptr = pj_pool_alloc(pool, 8);
	fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);

	rtpmap.pt = *fmt;
	rtpmap.clock_rate = codec_info->clock_rate;
	rtpmap.enc_name = codec_info->encoding_name;
	
	/* For audio codecs, rtpmap parameters denotes the number
	 * of channels, which can be omited if the value is 1.
	 */
	if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
	    codec_info->channel_cnt > 1)
	{
	    /* Can only support one digit channel count */
	    pj_assert(codec_info->channel_cnt < 10);

	    tmp_param[0] = '/';
	    tmp_param[1] = (char)('0' + codec_info->channel_cnt);

	    rtpmap.param.ptr = tmp_param;
	    rtpmap.param.slen = 2;

	} else {
	    rtpmap.param.slen = 0;
	}

	pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
	m->attr[m->attr_count++] = attr;

	/* Add fmtp mode where applicable */
	if (codec_param.setting.dec_fmtp_mode != 0) {
	    const pj_str_t fmtp = { "fmtp", 4 };
	    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));

	    attr->name = fmtp;
	    attr->value.ptr = pj_pool_alloc(pool, 32);
	    attr->value.slen = 
		pj_ansi_snprintf( attr->value.ptr, 32,
				  "%d mode=%d",
				  codec_info->pt,
				  codec_param.setting.dec_fmtp_mode);
	    m->attr[m->attr_count++] = attr;
	}
    }

    /* Add sendrecv attribute. */
    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
    attr->name = STR_SENDRECV;
    m->attr[m->attr_count++] = attr;

#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0

    /*
     * Add support telephony event
     */
    m->desc.fmt[m->desc.fmt_count++] = 
	pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);

    /* Add rtpmap. */
    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
    attr->name = pj_str("rtpmap");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR 
			 " telephone-event/8000");
    m->attr[m->attr_count++] = attr;

    /* Add fmtp */
    attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
    attr->name = pj_str("fmtp");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
    m->attr[m->attr_count++] = attr;
#endif

    /* Done */
    *p_sdp = sdp;

    return PJ_SUCCESS;

}
Esempio n. 13
0
/* Create m=video SDP media line */
PJ_DEF(pj_status_t) pjmedia_endpt_create_video_sdp(pjmedia_endpt *endpt,
																									 pj_pool_t *pool,
																									 const pjmedia_sock_info *si,
																									 unsigned options,
																									 pjmedia_sdp_media **p_m)
{


	const pj_str_t STR_VIDEO = { "video", 5 };
	pjmedia_sdp_media *m;
	pjmedia_vid_codec_info codec_info[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	unsigned codec_prio[PJMEDIA_VID_CODEC_MGR_MAX_CODECS];
	pjmedia_sdp_attr *attr;
	unsigned cnt, i;
	unsigned max_bitrate = 0;
	pj_status_t status;

	PJ_UNUSED_ARG(options);

	/* Make sure video codec manager is instantiated */
	if (!pjmedia_vid_codec_mgr_instance())
		pjmedia_vid_codec_mgr_create(endpt->pool, NULL);

	/* Create and init basic SDP media */
	m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
	status = init_sdp_media(m, pool, &STR_VIDEO, si);
	if (status != PJ_SUCCESS)
		return status;

	cnt = PJ_ARRAY_SIZE(codec_info);
	status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &cnt, 
		codec_info, codec_prio);

	/* Check that there are not too many codecs */
	PJ_ASSERT_RETURN(0 <= PJMEDIA_MAX_SDP_FMT,
		PJ_ETOOMANY);

	/* Add format, rtpmap, and fmtp (when applicable) for each codec */
	for (i=0; i<cnt; ++i) {
		pjmedia_sdp_rtpmap rtpmap;
		pjmedia_vid_codec_param codec_param;
		pj_str_t *fmt;
		pjmedia_video_format_detail *vfd;

		pj_bzero(&rtpmap, sizeof(rtpmap));

		if (codec_prio[i] == PJMEDIA_CODEC_PRIO_DISABLED)
			break;

		if (i > PJMEDIA_MAX_SDP_FMT) {
			/* Too many codecs, perhaps it is better to tell application by
			* returning appropriate status code.
			*/
			PJ_PERROR(3,(THIS_FILE, PJ_ETOOMANY,
				"Skipping some video codecs"));
			break;
		}

		/* Must support RTP packetization and bidirectional */
		if ((codec_info[i].packings & PJMEDIA_VID_PACKING_PACKETS) == 0 ||
			codec_info[i].dir != PJMEDIA_DIR_ENCODING_DECODING)
		{
			continue;
		}

		pjmedia_vid_codec_mgr_get_default_param(NULL, &codec_info[i],
			&codec_param);

		fmt = &m->desc.fmt[m->desc.fmt_count++];
		fmt->ptr = (char*) pj_pool_alloc(pool, 8);
		fmt->slen = pj_utoa(codec_info[i].pt, fmt->ptr);
		rtpmap.pt = *fmt;

		/* Encoding name */
		rtpmap.enc_name = codec_info[i].encoding_name;

		/* Clock rate */
		rtpmap.clock_rate = codec_info[i].clock_rate;

		if (codec_info[i].pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
			pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
			m->attr[m->attr_count++] = attr;
		}

		/* Add fmtp params */
		if (codec_param.dec_fmtp.cnt > 0) {
			enum { MAX_FMTP_STR_LEN = 160 };
			char buf[MAX_FMTP_STR_LEN];
			unsigned buf_len = 0, j;
			pjmedia_codec_fmtp *dec_fmtp = &codec_param.dec_fmtp;

			/* Print codec PT */
			buf_len += pj_ansi_snprintf(buf, 
				MAX_FMTP_STR_LEN - buf_len, 
				"%d", 
				codec_info[i].pt);

			for (j = 0; j < dec_fmtp->cnt; ++j) {
				unsigned test_len = 2;

				/* Check if buf still available */
				test_len = dec_fmtp->param[j].val.slen + 
					dec_fmtp->param[j].name.slen;
				if (test_len + buf_len >= MAX_FMTP_STR_LEN)
					return PJ_ETOOBIG;

				/* Print delimiter */
				buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					(j == 0?" ":";"));

				/* Print an fmtp param */
				if (dec_fmtp->param[j].name.slen)
					buf_len += pj_ansi_snprintf(
					&buf[buf_len],
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s=%.*s",
					(int)dec_fmtp->param[j].name.slen,
					dec_fmtp->param[j].name.ptr,
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
				else
					buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s", 
					(int)dec_fmtp->param[j].val.slen,
					dec_fmtp->param[j].val.ptr);
			}

			attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

			attr->name = pj_str("fmtp");
			attr->value = pj_strdup3(pool, buf);
			m->attr[m->attr_count++] = attr;
		}

		/* Find maximum bitrate in this media */
		vfd = pjmedia_format_get_video_format_detail(&codec_param.enc_fmt,
			PJ_TRUE);
		if (vfd && max_bitrate < vfd->max_bps)
			max_bitrate = vfd->max_bps;
	}

	/* Put bandwidth info in media level using bandwidth modifier "TIAS"
	* (RFC3890).
	*/
	if (max_bitrate) {
		const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
		pjmedia_sdp_bandw *b;

		b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
		b->modifier = STR_BANDW_MODIFIER;
		b->value = max_bitrate;
		m->bandw[m->bandw_count++] = b;
	}

	*p_m = m;
	return PJ_SUCCESS;
}
Esempio n. 14
0
PJ_DEF(void) pj_log( const char *sender, int level, 
		     const char *format, va_list marker)
{
    pj_time_val now;
    pj_parsed_time ptime;
    char *pre;
#if PJ_LOG_USE_STACK_BUFFER
    char log_buffer[PJ_LOG_MAX_SIZE];
#endif
    int len, print_len;

    PJ_CHECK_STACK();

    if (level > log_max_level)
	return;

    /* Get current date/time. */
    pj_gettimeofday(&now);
    pj_time_decode(&now, &ptime);

    pre = log_buffer;
    if (log_decor & PJ_LOG_HAS_DAY_NAME) {
	static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",
				       "Thu", "Fri", "Sat"};
	pj_ansi_strcpy(pre, wdays[ptime.wday]);
	pre += 3;
    }
    if (log_decor & PJ_LOG_HAS_YEAR) {
	*pre++ = ' ';
	pre += pj_utoa(ptime.year, pre);
    }
    if (log_decor & PJ_LOG_HAS_MONTH) {
	*pre++ = '-';
	pre += pj_utoa_pad(ptime.mon, pre, 2, '0');
    }
    if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {
	*pre++ = ' ';
	pre += pj_utoa_pad(ptime.day, pre, 2, '0');
    }
    if (log_decor & PJ_LOG_HAS_TIME) {
	*pre++ = ' ';
	pre += pj_utoa_pad(ptime.hour, pre, 2, '0');
	*pre++ = ':';
	pre += pj_utoa_pad(ptime.min, pre, 2, '0');
	*pre++ = ':';
	pre += pj_utoa_pad(ptime.sec, pre, 2, '0');
    }
    if (log_decor & PJ_LOG_HAS_MICRO_SEC) {
	*pre++ = '.';
	pre += pj_utoa_pad(ptime.msec, pre, 3, '0');
    }
    if (log_decor & PJ_LOG_HAS_SENDER) {
	enum { SENDER_WIDTH = 14 };
	int sender_len = strlen(sender);
	*pre++ = ' ';
	if (sender_len <= SENDER_WIDTH) {
	    while (sender_len < SENDER_WIDTH)
		*pre++ = ' ', ++sender_len;
	    while (*sender)
		*pre++ = *sender++;
	} else {
	    int i;
	    for (i=0; i<SENDER_WIDTH; ++i)
		*pre++ = *sender++;
	}
    }

    if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)
	*pre++ = ' ';

    len = pre - log_buffer;

    /* Print the whole message to the string log_buffer. */
    print_len = pj_ansi_vsnprintf(pre, sizeof(log_buffer)-len, format, 
				  marker);
    if (print_len < 0) {
	level = 1;
	print_len = pj_ansi_snprintf(pre, sizeof(log_buffer)-len, 
				     "<logging error: msg too long>");
    }
    len = len + print_len;
    if (len > 0 && len < (int)sizeof(log_buffer)-2) {
	if (log_decor & PJ_LOG_HAS_CR) {
	    log_buffer[len++] = '\r';
	}
	if (log_decor & PJ_LOG_HAS_NEWLINE) {
	    log_buffer[len++] = '\n';
	}
	log_buffer[len] = '\0';
    } else {
	len = sizeof(log_buffer)-1;
	if (log_decor & PJ_LOG_HAS_CR) {
	    log_buffer[sizeof(log_buffer)-3] = '\r';
	}
	if (log_decor & PJ_LOG_HAS_NEWLINE) {
	    log_buffer[sizeof(log_buffer)-2] = '\n';
	}
	log_buffer[sizeof(log_buffer)-1] = '\0';
    }

    if (log_writer)
	(*log_writer)(level, log_buffer, len);
}
Esempio n. 15
0
/**
 * Create a SDP session description that describes the endpoint
 * capability.
 */
PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
					      pj_pool_t *pool,
					      unsigned stream_cnt,
					      const pjmedia_sock_info sock_info[],
					      pjmedia_sdp_session **p_sdp )
{
    pj_time_val tv;
    unsigned i;
    const pj_sockaddr *addr0;
    pjmedia_sdp_session *sdp;
    pjmedia_sdp_media *m;
    pjmedia_sdp_attr *attr;

    /* Sanity check arguments */
    PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);

    /* Check that there are not too many codecs */
    PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
		     PJ_ETOOMANY);

    /* Create and initialize basic SDP session */
    sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);

    addr0 = &sock_info[0].rtp_addr_name;

    pj_gettimeofday(&tv);
    sdp->origin.user = pj_str("-");
    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
    sdp->origin.net_type = STR_IN;

    if (addr0->addr.sa_family == pj_AF_INET()) {
	sdp->origin.addr_type = STR_IP4;
	pj_strdup2(pool, &sdp->origin.addr, 
		   pj_inet_ntoa(addr0->ipv4.sin_addr));
    } else if (addr0->addr.sa_family == pj_AF_INET6()) {
	char tmp_addr[PJ_INET6_ADDRSTRLEN];

	sdp->origin.addr_type = STR_IP6;
	pj_strdup2(pool, &sdp->origin.addr, 
		   pj_sockaddr_print(addr0, tmp_addr, sizeof(tmp_addr), 0));

    } else {
	pj_assert(!"Invalid address family");
	return PJ_EAFNOTSUP;
    }

    sdp->name = STR_SDP_NAME;

    /* Since we only support one media stream at present, put the
     * SDP connection line in the session level.
     */
    sdp->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
    sdp->conn->net_type = sdp->origin.net_type;
    sdp->conn->addr_type = sdp->origin.addr_type;
    sdp->conn->addr = sdp->origin.addr;


    /* SDP time and attributes. */
    sdp->time.start = sdp->time.stop = 0;
    sdp->attr_count = 0;

    /* Create media stream 0: */

    sdp->media_count = 1;
    m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
    sdp->media[0] = m;

    /* Standard media info: */
    pj_strdup(pool, &m->desc.media, &STR_AUDIO);
    m->desc.port = pj_sockaddr_get_port(addr0);
    m->desc.port_count = 1;
    pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);

    /* Init media line and attribute list. */
    m->desc.fmt_count = 0;
    m->attr_count = 0;

    /* Add "rtcp" attribute */
#if defined(PJMEDIA_HAS_RTCP_IN_SDP) && PJMEDIA_HAS_RTCP_IN_SDP!=0
    if (sock_info->rtcp_addr_name.addr.sa_family != 0) {
	attr = pjmedia_sdp_attr_create_rtcp(pool, &sock_info->rtcp_addr_name);
	if (attr)
	    pjmedia_sdp_attr_add(&m->attr_count, m->attr, attr);
    }
#endif

    /* Add format, rtpmap, and fmtp (when applicable) for each codec */
    for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {

	pjmedia_codec_info *codec_info;
	pjmedia_sdp_rtpmap rtpmap;
	char tmp_param[3];
	pjmedia_sdp_attr *attr;
	pjmedia_codec_param codec_param;
	pj_str_t *fmt;

	if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
	    break;

	codec_info = &endpt->codec_mgr.codec_desc[i].info;
	pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
					    &codec_param);
	fmt = &m->desc.fmt[m->desc.fmt_count++];

	fmt->ptr = (char*) pj_pool_alloc(pool, 8);
	fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);

	rtpmap.pt = *fmt;
	rtpmap.enc_name = codec_info->encoding_name;

#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
	if (codec_info->pt == PJMEDIA_RTP_PT_G722)
	    rtpmap.clock_rate = 8000;
	else
	    rtpmap.clock_rate = codec_info->clock_rate;
#else
	rtpmap.clock_rate = codec_info->clock_rate;
#endif

	/* For audio codecs, rtpmap parameters denotes the number
	 * of channels, which can be omited if the value is 1.
	 */
	if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
	    codec_info->channel_cnt > 1)
	{
	    /* Can only support one digit channel count */
	    pj_assert(codec_info->channel_cnt < 10);

	    tmp_param[0] = (char)('0' + codec_info->channel_cnt);

	    rtpmap.param.ptr = tmp_param;
	    rtpmap.param.slen = 1;

	} else {
	    rtpmap.param.slen = 0;
	}

	if (codec_info->pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
	    pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
	    m->attr[m->attr_count++] = attr;
	}

	/* Add fmtp params */
	if (codec_param.setting.dec_fmtp.cnt > 0) {
	    enum { MAX_FMTP_STR_LEN = 160 };
	    char buf[MAX_FMTP_STR_LEN];
	    unsigned buf_len = 0, i;
	    pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;

	    /* Print codec PT */
	    buf_len += pj_ansi_snprintf(buf, 
					MAX_FMTP_STR_LEN - buf_len, 
					"%d", 
					codec_info->pt);

	    for (i = 0; i < dec_fmtp->cnt; ++i) {
		unsigned test_len = 2;

		/* Check if buf still available */
		test_len = dec_fmtp->param[i].val.slen + 
			   dec_fmtp->param[i].name.slen;
		if (test_len + buf_len >= MAX_FMTP_STR_LEN)
		    return PJ_ETOOBIG;

		/* Print delimiter */
		buf_len += pj_ansi_snprintf(&buf[buf_len], 
					    MAX_FMTP_STR_LEN - buf_len,
					    (i == 0?" ":";"));

		/* Print an fmtp param */
		if (dec_fmtp->param[i].name.slen)
		    buf_len += pj_ansi_snprintf(
					    &buf[buf_len],
					    MAX_FMTP_STR_LEN - buf_len,
					    "%.*s=%.*s",
					    (int)dec_fmtp->param[i].name.slen,
					    dec_fmtp->param[i].name.ptr,
					    (int)dec_fmtp->param[i].val.slen,
					    dec_fmtp->param[i].val.ptr);
		else
		    buf_len += pj_ansi_snprintf(&buf[buf_len], 
					    MAX_FMTP_STR_LEN - buf_len,
					    "%.*s", 
					    (int)dec_fmtp->param[i].val.slen,
					    dec_fmtp->param[i].val.ptr);
	    }

	    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

	    attr->name = pj_str("fmtp");
	    attr->value = pj_strdup3(pool, buf);
	    m->attr[m->attr_count++] = attr;
	}
    }

    /* Add sendrecv attribute. */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = STR_SENDRECV;
    m->attr[m->attr_count++] = attr;

#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
    PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0

    /*
     * Add support telephony event
     */
    m->desc.fmt[m->desc.fmt_count++] = 
	pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);

    /* Add rtpmap. */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = pj_str("rtpmap");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR 
			 " telephone-event/8000");
    m->attr[m->attr_count++] = attr;

    /* Add fmtp */
    attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
    attr->name = pj_str("fmtp");
    attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
    m->attr[m->attr_count++] = attr;
#endif

    /* Done */
    *p_sdp = sdp;

    return PJ_SUCCESS;

}
Esempio n. 16
0
static int multipart_print_body(struct pjsip_msg_body *msg_body,
			        char *buf, pj_size_t size)
{
    const struct multipart_data *m_data;
    pj_str_t clen_hdr =  { "Content-Length: ", 16};
    pjsip_multipart_part *part;
    char *p = buf, *end = buf+size;

#define SIZE_LEFT()	(end-p)

    m_data = (const struct multipart_data*)msg_body->data;

    PJ_ASSERT_RETURN(m_data && !pj_list_empty(&m_data->part_head), PJ_EINVAL);

    part = m_data->part_head.next;
    while (part != &m_data->part_head) {
	enum { CLEN_SPACE = 5 };
	char *clen_pos;
	const pjsip_hdr *hdr;

	clen_pos = NULL;

	/* Print delimiter */
	if (SIZE_LEFT() <= (m_data->boundary.slen+8) << 1)
	    return -1;
	*p++ = 13; *p++ = 10; *p++ = '-'; *p++ = '-';
	pj_memcpy(p, m_data->boundary.ptr, m_data->boundary.slen);
	p += m_data->boundary.slen;
	*p++ = 13; *p++ = 10;

	/* Print optional headers */
	hdr = part->hdr.next;
	while (hdr != &part->hdr) {
	    int printed = pjsip_hdr_print_on((pjsip_hdr*)hdr, p,
	                                     SIZE_LEFT()-2);
	    if (printed < 0)
		return -1;
	    p += printed;
	    *p++ = '\r';
	    *p++ = '\n';
	    hdr = hdr->next;
	}

	/* Automaticly adds Content-Type and Content-Length headers, only
	 * if content_type is set in the message body.
	 */
	if (part->body && part->body->content_type.type.slen) {
	    pj_str_t ctype_hdr = { "Content-Type: ", 14};
	    const pjsip_media_type *media = &part->body->content_type;

	    if (pjsip_use_compact_form) {
		ctype_hdr.ptr = "c: ";
		ctype_hdr.slen = 3;
	    }

	    /* Add Content-Type header. */
	    if ( (end-p) < 24 + media->type.slen + media->subtype.slen) {
		return -1;
	    }
	    pj_memcpy(p, ctype_hdr.ptr, ctype_hdr.slen);
	    p += ctype_hdr.slen;
	    p += pjsip_media_type_print(p, (unsigned)(end-p), media);
	    *p++ = '\r';
	    *p++ = '\n';

	    /* Add Content-Length header. */
	    if ((end-p) < clen_hdr.slen + 12 + 2) {
		return -1;
	    }
	    pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);
	    p += clen_hdr.slen;

	    /* Print blanks after "Content-Length:", this is where we'll put
	     * the content length value after we know the length of the
	     * body.
	     */
	    pj_memset(p, ' ', CLEN_SPACE);
	    clen_pos = p;
	    p += CLEN_SPACE;
	    *p++ = '\r';
	    *p++ = '\n';
	}

	/* Empty newline */
	*p++ = 13; *p++ = 10;

	/* Print the body */
	pj_assert(part->body != NULL);
	if (part->body) {
	    int printed = part->body->print_body(part->body, p, SIZE_LEFT());
	    if (printed < 0)
		return -1;
	    p += printed;

	    /* Now that we have the length of the body, print this to the
	     * Content-Length header.
	     */
	    if (clen_pos) {
		char tmp[16];
		int len;

		len = pj_utoa(printed, tmp);
		if (len > CLEN_SPACE) len = CLEN_SPACE;
		pj_memcpy(clen_pos+CLEN_SPACE-len, tmp, len);
	    }
	}

	part = part->next;
    }

    /* Print closing delimiter */
    if (SIZE_LEFT() < m_data->boundary.slen+8)
	return -1;
    *p++ = 13; *p++ = 10; *p++ = '-'; *p++ = '-';
    pj_memcpy(p, m_data->boundary.ptr, m_data->boundary.slen);
    p += m_data->boundary.slen;
    *p++ = '-'; *p++ = '-'; *p++ = 13; *p++ = 10;

#undef SIZE_LEFT

    return (int)(p - buf);
}
Esempio n. 17
0
 //
 // Convert from unsigned long.
 //
 void from_ulong(unsigned long value)
 {
     slen = pj_utoa(value, ptr);
 }
Esempio n. 18
0
PJ_DEF(void) pj_log( const char *sender, int level, 
		     const char *format, va_list marker)
{
    pj_time_val now;
    pj_parsed_time ptime;
    char *pre;
#if PJ_LOG_USE_STACK_BUFFER
    char log_buffer[PJ_LOG_MAX_SIZE];
#endif
    int saved_level, len, print_len;

    PJ_CHECK_STACK();

    if (level > pj_log_max_level)
	return;

    if (is_logging_suspended())
	return;

    /* Temporarily disable logging for this thread. Some of PJLIB APIs that
     * this function calls below will recursively call the logging function 
     * back, hence it will cause infinite recursive calls if we allow that.
     */
    suspend_logging(&saved_level);

    /* Get current date/time. */
    pj_gettimeofday(&now);
    pj_time_decode(&now, &ptime);

    pre = log_buffer;
    if (log_decor & PJ_LOG_HAS_LEVEL_TEXT) {
	static const char *ltexts[] = { "FATAL:", "ERROR:", " WARN:", 
			      " INFO:", "DEBUG:", "TRACE:", "DETRC:"};
	pj_ansi_strcpy(pre, ltexts[level]);
	pre += 6;
    }
    if (log_decor & PJ_LOG_HAS_DAY_NAME) {
	static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",
				       "Thu", "Fri", "Sat"};
	pj_ansi_strcpy(pre, wdays[ptime.wday]);
	pre += 3;
    }
    if (log_decor & PJ_LOG_HAS_YEAR) {
	*pre++ = ' ';
	pre += pj_utoa(ptime.year, pre);
    }
    if (log_decor & PJ_LOG_HAS_MONTH) {
	*pre++ = '-';
	pre += pj_utoa_pad(ptime.mon+1, pre, 2, '0');
    }
    if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {
	*pre++ = '-';
	pre += pj_utoa_pad(ptime.day, pre, 2, '0');
    }
    if (log_decor & PJ_LOG_HAS_TIME) {
	*pre++ = ' ';
	pre += pj_utoa_pad(ptime.hour, pre, 2, '0');
	*pre++ = ':';
	pre += pj_utoa_pad(ptime.min, pre, 2, '0');
	*pre++ = ':';
	pre += pj_utoa_pad(ptime.sec, pre, 2, '0');
    }
    if (log_decor & PJ_LOG_HAS_MICRO_SEC) {
	*pre++ = '.';
	pre += pj_utoa_pad(ptime.msec, pre, 3, '0');
    }
    if (log_decor & PJ_LOG_HAS_SENDER) {
	enum { SENDER_WIDTH = 14 };
	int sender_len = strlen(sender);
	*pre++ = ' ';
	if (sender_len <= SENDER_WIDTH) {
	    while (sender_len < SENDER_WIDTH)
		*pre++ = ' ', ++sender_len;
	    while (*sender)
		*pre++ = *sender++;
	} else {
	    int i;
	    for (i=0; i<SENDER_WIDTH; ++i)
		*pre++ = *sender++;
	}
    }
    if (log_decor & PJ_LOG_HAS_THREAD_ID) {
	enum { THREAD_WIDTH = 12 };
	const char *thread_name = pj_thread_get_name(pj_thread_this());
	int thread_len = strlen(thread_name);
	*pre++ = ' ';
	if (thread_len <= THREAD_WIDTH) {
	    while (thread_len < THREAD_WIDTH)
		*pre++ = ' ', ++thread_len;
	    while (*thread_name)
		*pre++ = *thread_name++;
	} else {
	    int i;
	    for (i=0; i<THREAD_WIDTH; ++i)
		*pre++ = *thread_name++;
	}
    }

    if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)
	*pre++ = ' ';

    if (log_decor & PJ_LOG_HAS_SPACE) {
	*pre++ = ' ';
    }

    len = pre - log_buffer;

    /* Print the whole message to the string log_buffer. */
    print_len = pj_ansi_vsnprintf(pre, sizeof(log_buffer)-len, format, 
				  marker);
    if (print_len < 0) {
	level = 1;
	print_len = pj_ansi_snprintf(pre, sizeof(log_buffer)-len, 
				     "<logging error: msg too long>");
    }
    len = len + print_len;
    if (len > 0 && len < (int)sizeof(log_buffer)-2) {
	if (log_decor & PJ_LOG_HAS_CR) {
	    log_buffer[len++] = '\r';
	}
	if (log_decor & PJ_LOG_HAS_NEWLINE) {
	    log_buffer[len++] = '\n';
	}
	log_buffer[len] = '\0';
    } else {
	len = sizeof(log_buffer)-1;
	if (log_decor & PJ_LOG_HAS_CR) {
	    log_buffer[sizeof(log_buffer)-3] = '\r';
	}
	if (log_decor & PJ_LOG_HAS_NEWLINE) {
	    log_buffer[sizeof(log_buffer)-2] = '\n';
	}
	log_buffer[sizeof(log_buffer)-1] = '\0';
    }

    /* It should be safe to resume logging at this point. Application can
     * recursively call the logging function inside the callback.
     */
    resume_logging(&saved_level);

    if (log_writer)
	(*log_writer)(level, log_buffer, len);
}
Esempio n. 19
0
static pj_ssize_t pjsip_url_print(  pjsip_uri_context_e context,
                                    const pjsip_sip_uri *url,
                                    char *buf, pj_size_t size)
{
    int printed;
    char *startbuf = buf;
    char *endbuf = buf+size;
    const pj_str_t *scheme;
    const pjsip_parser_const_t *pc = pjsip_parser_const();

    *buf = '\0';

    /* Print scheme ("sip:" or "sips:") */
    scheme = pjsip_uri_get_scheme(url);
    copy_advance_check(buf, *scheme);
    *buf++ = ':';

    /* Print "user:password@", if any. */
    if (url->user.slen) {
        copy_advance_escape(buf, url->user, pc->pjsip_USER_SPEC);
        if (url->passwd.slen) {
            *buf++ = ':';
            copy_advance_escape(buf, url->passwd, pc->pjsip_PASSWD_SPEC);
        }

        *buf++ = '@';
    }

    /* Print host. */
    pj_assert(url->host.slen != 0);
    /* Detect IPv6 IP address */
    if (pj_memchr(url->host.ptr, ':', url->host.slen)) {
        copy_advance_pair_quote_cond(buf, "", 0, url->host, '[', ']');
    } else {
        copy_advance_check(buf, url->host);
    }

    /* Only print port if it is explicitly specified.
     * Port is not allowed in To and From header, see Table 1 in
     * RFC 3261 Section 19.1.1
     */
    /* Note: ticket #1141 adds run-time setting to allow port number to
     * appear in From/To header. Default is still false.
     */
    if (url->port &&
            (context != PJSIP_URI_IN_FROMTO_HDR ||
             pjsip_cfg()->endpt.allow_port_in_fromto_hdr))
    {
        if (endbuf - buf < 10)
            return -1;

        *buf++ = ':';
        printed = pj_utoa(url->port, buf);
        buf += printed;
    }

    /* User param is allowed in all contexes */
    copy_advance_pair_check(buf, ";user="******";method=", 8, url->method_param,
                                 pc->pjsip_PARAM_CHAR_SPEC);
    }

    /* Transport is not allowed in From/To header. */
    if (context != PJSIP_URI_IN_FROMTO_HDR) {
        copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param,
                                 pc->pjsip_PARAM_CHAR_SPEC);
    }

    /* TTL param is not allowed in From, To, Route, and Record-Route header. */
    if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
            context != PJSIP_URI_IN_ROUTING_HDR)
    {
        if (endbuf - buf < 15)
            return -1;
        pj_memcpy(buf, ";ttl=", 5);
        printed = pj_utoa(url->ttl_param, buf+5);
        buf += printed + 5;
    }

    /* maddr param is not allowed in From and To header. */
    if (context != PJSIP_URI_IN_FROMTO_HDR && url->maddr_param.slen) {
        /* Detect IPv6 IP address */
        if (pj_memchr(url->maddr_param.ptr, ':', url->maddr_param.slen)) {
            copy_advance_pair_quote_cond(buf, ";maddr=", 7, url->maddr_param,
                                         '[', ']');
        } else {
            copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param,
                                     pc->pjsip_PARAM_CHAR_SPEC);
        }
    }

    /* lr param is not allowed in From, To, and Contact header. */
    if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&
            context != PJSIP_URI_IN_CONTACT_HDR)
    {
        pj_str_t lr = { ";lr", 3 };
        if (endbuf - buf < 3)
            return -1;
        copy_advance_check(buf, lr);
    }

    /* Other param. */
    printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf,
                                   &pc->pjsip_PARAM_CHAR_SPEC,
                                   &pc->pjsip_PARAM_CHAR_SPEC, ';');
    if (printed < 0)
        return -1;
    buf += printed;

    /* Header param.
     * Header param is only allowed in these contexts:
     *	- PJSIP_URI_IN_CONTACT_HDR
     *	- PJSIP_URI_IN_OTHER
     */
    if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) {
        printed = pjsip_param_print_on(&url->header_param, buf, endbuf-buf,
                                       &pc->pjsip_HDR_CHAR_SPEC,
                                       &pc->pjsip_HDR_CHAR_SPEC, '?');
        if (printed < 0)
            return -1;
        buf += printed;
    }

    *buf = '\0';
    return buf-startbuf;
}
Esempio n. 20
0
PJ_DEF(pj_status_t) pjmedia_codec_silk_init(pjmedia_endpt *endpt)
{
    pjmedia_codec_mgr *codec_mgr;
    pj_status_t status;

    if (silk_factory.endpt != NULL) {
	/* Already initialized. */
	return PJ_SUCCESS;
    }

    /* Init factory */
    silk_factory.base.op = &silk_factory_op;
    silk_factory.base.factory_data = NULL;
    silk_factory.endpt = endpt;

    /* Create pool */
    silk_factory.pool = pjmedia_endpt_create_pool(endpt, "silk codecs", 4000, 4000);
    if (!silk_factory.pool)
	return PJ_ENOMEM;

    /* Init list */
    pj_list_init(&silk_factory.codec_list);

    /* Create mutex. */
    status = pj_mutex_create_simple(silk_factory.pool, "silk codecs",
				    &silk_factory.mutex);
    if (status != PJ_SUCCESS)
	goto on_error;
    PJ_LOG(5, (THIS_FILE, "Init silk"));

    /* Table from silk docs
    				| fs (Hz) | BR (kbps)
    ----------------+---------+----------
    Narrowband		|    8000 |  5 - 20
    Mediumband		|   12000 |  7 - 25
    Wideband		|   16000 |  8 - 30
    Super Wideband	|   24000 | 20 - 40
    */
    // The max_bitrate is based on the maximum bitrate that can be used for the encoder.
    // BTW, if a remote side send us something very big, we will not get lost.
    // If such a remote side send us big packets it could be considered unefficient.
    // On our side we set for bitrate the medium value of bitrate for each clock rate based
    // on table above.
    struct silk_param *silk_param;
    silk_param = &silk_factory.silk_param[PARAM_NB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_NB;
    silk_param->clock_rate = 8000;
    silk_param->bitrate = 13000;
	pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
	silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
	silk_param->packet_size_ms = FRAME_LENGTH_MS;
	silk_param->complexity = 2;
	silk_param->enabled = 1;

    silk_param = &silk_factory.silk_param[PARAM_MB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_MB;
    silk_param->clock_rate = 12000;
    silk_param->bitrate = 16000;
    pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
    silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
    silk_param->packet_size_ms = FRAME_LENGTH_MS;
    silk_param->complexity = 2;
    silk_param->enabled = 1;

    silk_param = &silk_factory.silk_param[PARAM_WB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_WB;
	silk_param->clock_rate = 16000;
	silk_param->bitrate = 19000;
	pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
	silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
	silk_param->packet_size_ms = FRAME_LENGTH_MS;
	silk_param->complexity = 2;
	silk_param->enabled = 1;

    silk_param = &silk_factory.silk_param[PARAM_UWB];
    silk_param->pt = PJMEDIA_RTP_PT_SILK_UWB;
    silk_param->clock_rate = 24000;
    silk_param->bitrate = 30000;
	pj_utoa(silk_param->bitrate, silk_param->bitrate_str);
    silk_param->max_bitrate = SILK_MAX_CODER_BITRATE;
	silk_param->packet_size_ms = FRAME_LENGTH_MS;
	silk_param->complexity = 2;
	silk_param->enabled = 1;


    /* Get the codec manager. */
    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
    if (!codec_mgr) {
	return PJ_EINVALIDOP;
    }

    PJ_LOG(5, (THIS_FILE, "Init silk > DONE"));

    /* Register codec factory to endpoint. */
    status = pjmedia_codec_mgr_register_factory(codec_mgr,
						&silk_factory.base);
    if (status != PJ_SUCCESS)
	return status;

    return PJ_SUCCESS;

on_error:
    if (silk_factory.mutex) {
	pj_mutex_destroy(silk_factory.mutex);
	silk_factory.mutex = NULL;
    }
    if (silk_factory.pool) {
	pj_pool_release(silk_factory.pool);
	silk_factory.pool = NULL;
    }

    return status;
}
Esempio n. 21
0
/* Create m=audio SDP media line */
PJ_DEF(pj_status_t) pjmedia_endpt_create_audio_sdp(pjmedia_endpt *endpt,
																									 pj_pool_t *pool,
																									 const pjmedia_sock_info *si,
																									 unsigned options,
																									 pjmedia_sdp_media **p_m)
{
	const pj_str_t STR_AUDIO = { "audio", 5 };
	pjmedia_sdp_media *m;
	pjmedia_sdp_attr *attr;
	unsigned i;
	unsigned max_bitrate = 0;
	pj_status_t status;

	PJ_UNUSED_ARG(options);

	/* Check that there are not too many codecs */
	PJ_ASSERT_RETURN(endpt->codec_mgr.codec_cnt <= PJMEDIA_MAX_SDP_FMT,
		PJ_ETOOMANY);

	/* Create and init basic SDP media */
	m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
	status = init_sdp_media(m, pool, &STR_AUDIO, si);
	if (status != PJ_SUCCESS)
		return status;

	/* Add format, rtpmap, and fmtp (when applicable) for each codec */
	for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {

		pjmedia_codec_info *codec_info;
		pjmedia_sdp_rtpmap rtpmap;
		char tmp_param[3];
		pjmedia_codec_param codec_param;
		pj_str_t *fmt;

		if (endpt->codec_mgr.codec_desc[i].prio == PJMEDIA_CODEC_PRIO_DISABLED)
			break;

		codec_info = &endpt->codec_mgr.codec_desc[i].info;
		pjmedia_codec_mgr_get_default_param(&endpt->codec_mgr, codec_info,
			&codec_param);
		fmt = &m->desc.fmt[m->desc.fmt_count++];

		fmt->ptr = (char*) pj_pool_alloc(pool, 8);
		fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);

		rtpmap.pt = *fmt;
		rtpmap.enc_name = codec_info->encoding_name;

#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
		if (codec_info->pt == PJMEDIA_RTP_PT_G722)
			rtpmap.clock_rate = 8000;
		else
			rtpmap.clock_rate = codec_info->clock_rate;
#else
		rtpmap.clock_rate = codec_info->clock_rate;
#endif

		/* For audio codecs, rtpmap parameters denotes the number
		* of channels, which can be omited if the value is 1.
		*/
		if (codec_info->type == PJMEDIA_TYPE_AUDIO &&
			codec_info->channel_cnt > 1)
		{
			/* Can only support one digit channel count */
			pj_assert(codec_info->channel_cnt < 10);

			tmp_param[0] = (char)('0' + codec_info->channel_cnt);

			rtpmap.param.ptr = tmp_param;
			rtpmap.param.slen = 1;

		} else {
			rtpmap.param.ptr = "";
			rtpmap.param.slen = 0;
		}

		if (codec_info->pt >= 96 || pjmedia_add_rtpmap_for_static_pt) {
			pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
			m->attr[m->attr_count++] = attr;
		}

		/* Add fmtp params */
		if (codec_param.setting.dec_fmtp.cnt > 0) {
			enum { MAX_FMTP_STR_LEN = 160 };
			char buf[MAX_FMTP_STR_LEN];
			unsigned buf_len = 0, i;
			pjmedia_codec_fmtp *dec_fmtp = &codec_param.setting.dec_fmtp;

			/* Print codec PT */
			buf_len += pj_ansi_snprintf(buf, 
				MAX_FMTP_STR_LEN - buf_len, 
				"%d", 
				codec_info->pt);

			for (i = 0; i < dec_fmtp->cnt; ++i) {
				unsigned test_len = 2;

				/* Check if buf still available */
				test_len = dec_fmtp->param[i].val.slen + 
					dec_fmtp->param[i].name.slen;
				if (test_len + buf_len >= MAX_FMTP_STR_LEN)
					return PJ_ETOOBIG;

				/* Print delimiter */
				buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					(i == 0?" ":";"));

				/* Print an fmtp param */
				if (dec_fmtp->param[i].name.slen)
					buf_len += pj_ansi_snprintf(
					&buf[buf_len],
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s=%.*s",
					(int)dec_fmtp->param[i].name.slen,
					dec_fmtp->param[i].name.ptr,
					(int)dec_fmtp->param[i].val.slen,
					dec_fmtp->param[i].val.ptr);
				else
					buf_len += pj_ansi_snprintf(&buf[buf_len], 
					MAX_FMTP_STR_LEN - buf_len,
					"%.*s", 
					(int)dec_fmtp->param[i].val.slen,
					dec_fmtp->param[i].val.ptr);
			}

			attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);

			attr->name = pj_str("fmtp");
			attr->value = pj_strdup3(pool, buf);
			m->attr[m->attr_count++] = attr;
		}

		/* Find maximum bitrate in this media */
		if (max_bitrate < codec_param.info.max_bps)
			max_bitrate = codec_param.info.max_bps;
	}

#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \
	PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0
	/*
	* Add support telephony event
	*/
	if (endpt->has_telephone_event) {
		m->desc.fmt[m->desc.fmt_count++] =
			pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR);

		/* Add rtpmap. */
		attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
		attr->name = pj_str("rtpmap");
		attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR
			" telephone-event/8000");
		m->attr[m->attr_count++] = attr;

		/* Add fmtp */
		attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
		attr->name = pj_str("fmtp");
		attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15");
		m->attr[m->attr_count++] = attr;
	}
#endif

	/* Put bandwidth info in media level using bandwidth modifier "TIAS"
	* (RFC3890).
	*/
	if (max_bitrate) {
		const pj_str_t STR_BANDW_MODIFIER = { "TIAS", 4 };
		pjmedia_sdp_bandw *b;

		b = PJ_POOL_ALLOC_T(pool, pjmedia_sdp_bandw);
		b->modifier = STR_BANDW_MODIFIER;
		b->value = max_bitrate;
		m->bandw[m->bandw_count++] = b;
	}

	*p_m = m;
	return PJ_SUCCESS;
}
Esempio n. 22
0
int string_test(void)
{
    const pj_str_t hello_world = { HELLO_WORLD, HELLO_WORLD_LEN };
    const pj_str_t just_hello = { JUST_HELLO, JUST_HELLO_LEN };
    pj_str_t s1, s2, s3, s4, s5;
    enum { RCOUNT = 10, RLEN = 16 };
    pj_str_t random[RCOUNT];
    pj_pool_t *pool;
    int i;

    pool = pj_pool_create(mem, SNULL, 4096, 0, SNULL);
    if (!pool) return -5;
    
    /* 
     * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(), 
     * pj_strncmp(), pj_strchr() 
     */
    s1 = pj_str(HELLO_WORLD);
    if (pj_strcmp(&s1, &hello_world) != 0)
	return -10;
    if (pj_stricmp(&s1, &hello_world) != 0)
	return -20;
    if (pj_strcmp(&s1, &just_hello) <= 0)
	return -30;
    if (pj_stricmp(&s1, &just_hello) <= 0)
	return -40;
    if (pj_strlen(&s1) != strlen(HELLO_WORLD))
	return -50;
    if (pj_strncmp(&s1, &hello_world, 5) != 0)
	return -60;
    if (pj_strnicmp(&s1, &hello_world, 5) != 0)
	return -70;
    if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1)
	return -80;

    /* 
     * pj_strdup() 
     */
    if (!pj_strdup(pool, &s2, &s1))
	return -100;
    if (pj_strcmp(&s1, &s2) != 0)
	return -110;
    
    /* 
     * pj_strcpy(), pj_strcat() 
     */
    s3.ptr = (char*) pj_pool_alloc(pool, 256);
    if (!s3.ptr) 
	return -200;
    pj_strcpy(&s3, &s2);
    pj_strcat(&s3, &just_hello);

    if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0)
	return -210;

    /* 
     * pj_strdup2(), pj_strtrim(). 
     */
    pj_strdup2(pool, &s4, " " HELLO_WORLD "\t ");
    pj_strtrim(&s4);
    if (pj_strcmp2(&s4, HELLO_WORLD) != 0)
	return -250;

    /* 
     * pj_utoa() 
     */
    s5.ptr = (char*) pj_pool_alloc(pool, 16);
    if (!s5.ptr)
	return -270;
    s5.slen = pj_utoa(UL_VALUE, s5.ptr);

    /* 
     * pj_strtoul() 
     */
    if (pj_strtoul(&s5) != UL_VALUE)
	return -280;

    /*
     * pj_strtoul2()
     */
    s5 = pj_str("123456");

    pj_strtoul2(&s5, SNULL, 10);	/* Crash test */

    if (pj_strtoul2(&s5, &s4, 10) != 123456UL)
	return -290;
    if (s4.slen != 0)
	return -291;
    if (pj_strtoul2(&s5, &s4, 16) != 0x123456UL)
	return -292;

    s5 = pj_str("0123ABCD");
    if (pj_strtoul2(&s5, &s4, 10) != 123)
	return -293;
    if (s4.slen != 4)
	return -294;
    if (s4.ptr == SNULL || *s4.ptr != 'A')
	return -295;
    if (pj_strtoul2(&s5, &s4, 16) != 0x123ABCDUL)
	return -296;
    if (s4.slen != 0)
	return -297;

    /* 
     * pj_create_random_string() 
     * Check that no duplicate strings are returned.
     */
    for (i=0; i<RCOUNT; ++i) {
	int j;
	
	random[i].ptr = (char*) pj_pool_alloc(pool, RLEN);
	if (!random[i].ptr)
	    return -320;

        random[i].slen = RLEN;
	pj_create_random_string(random[i].ptr, RLEN);

	for (j=0; j<i; ++j) {
	    if (pj_strcmp(&random[i], &random[j])==0)
		return -330;
	}
    }

    /* Done. */
    pj_pool_release(pool);

    /* Case sensitive comparison test. */
    i = strcmp_test();
    if (i != 0)
	return i;

    /* Caseless comparison test. */
    i = stricmp_test();
    if (i != 0)
	return i;

    return 0;
}