⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjsua_core.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 4 页
字号:


    /* Create default configurations when the config is not supplied */

    if (ua_cfg == NULL) {
	pjsua_config_default(&default_cfg);
	ua_cfg = &default_cfg;
    }

    if (media_cfg == NULL) {
	pjsua_media_config_default(&default_media_cfg);
	media_cfg = &default_media_cfg;
    }

    /* Initialize logging first so that info/errors can be captured */
    if (log_cfg) {
	status = pjsua_reconfigure_logging(log_cfg);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
    }

    /* If nameserver is configured, create DNS resolver instance and
     * set it to be used by SIP resolver.
     */
    if (ua_cfg->nameserver_count) {
#if PJSIP_HAS_RESOLVER
	unsigned i;

	/* Create DNS resolver */
	status = pjsip_endpt_create_resolver(pjsua_var.endpt, 
					     &pjsua_var.resolver);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Error creating resolver", status);
	    return status;
	}

	/* Configure nameserver for the DNS resolver */
	status = pj_dns_resolver_set_ns(pjsua_var.resolver, 
					ua_cfg->nameserver_count,
					ua_cfg->nameserver, NULL);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Error setting nameserver", status);
	    return status;
	}

	/* Set this DNS resolver to be used by the SIP resolver */
	status = pjsip_endpt_set_resolver(pjsua_var.endpt, pjsua_var.resolver);
	if (status != PJ_SUCCESS) {
	    pjsua_perror(THIS_FILE, "Error setting DNS resolver", status);
	    return status;
	}

	/* Print nameservers */
	for (i=0; i<ua_cfg->nameserver_count; ++i) {
	    PJ_LOG(4,(THIS_FILE, "Nameserver %.*s added",
		      (int)ua_cfg->nameserver[i].slen,
		      ua_cfg->nameserver[i].ptr));
	}
#else
	PJ_LOG(2,(THIS_FILE, 
		  "DNS resolver is disabled (PJSIP_HAS_RESOLVER==0)"));
#endif
    }

    /* Init SIP UA: */

    /* Initialize transaction layer: */
    status = pjsip_tsx_layer_init_module(pjsua_var.endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);


    /* Initialize UA layer module: */
    status = pjsip_ua_init_module( pjsua_var.endpt, NULL );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);


    /* Initialize Replaces support. */
    status = pjsip_replaces_init_module( pjsua_var.endpt );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);


    /* Initialize and register PJSUA application module. */
    {
	const pjsip_module mod_initializer = 
	{
	NULL, NULL,		    /* prev, next.			*/
	{ "mod-pjsua", 9 },	    /* Name.				*/
	-1,			    /* Id				*/
	PJSIP_MOD_PRIORITY_APPLICATION,	/* Priority			*/
	NULL,			    /* load()				*/
	NULL,			    /* start()				*/
	NULL,			    /* stop()				*/
	NULL,			    /* unload()				*/
	&mod_pjsua_on_rx_request,   /* on_rx_request()			*/
	&mod_pjsua_on_rx_response,  /* on_rx_response()			*/
	NULL,			    /* on_tx_request.			*/
	NULL,			    /* on_tx_response()			*/
	NULL,			    /* on_tsx_state()			*/
	};

	pjsua_var.mod = mod_initializer;

	status = pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_var.mod);
	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
    }

    

    /* Initialize PJSUA call subsystem: */
    status = pjsua_call_subsys_init(ua_cfg);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Start resolving STUN server */
    status = pjsua_resolve_stun_server(PJ_FALSE);
    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
	pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
	return status;
    }

    /* Initialize PJSUA media subsystem */
    status = pjsua_media_subsys_init(media_cfg);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Init core SIMPLE module : */
    status = pjsip_evsub_init_module(pjsua_var.endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);


    /* Init presence module: */
    status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance());
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /* Init PUBLISH module */
    pjsip_publishc_init_module(pjsua_var.endpt);

    /* Init xfer/REFER module */
    status = pjsip_xfer_init_module( pjsua_var.endpt );
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

    /* Init pjsua presence handler: */
    status = pjsua_pres_init();
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Init out-of-dialog MESSAGE request handler. */
    status = pjsua_im_init();
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Register OPTIONS handler */
    pjsip_endpt_register_module(pjsua_var.endpt, &pjsua_options_handler);

    /* Add OPTIONS in Allow header */
    pjsip_endpt_add_capability(pjsua_var.endpt, NULL, PJSIP_H_ALLOW,
			       NULL, 1, &STR_OPTIONS);

    /* Start worker thread if needed. */
    if (pjsua_var.ua_cfg.thread_cnt) {
	unsigned i;

	if (pjsua_var.ua_cfg.thread_cnt > PJ_ARRAY_SIZE(pjsua_var.thread))
	    pjsua_var.ua_cfg.thread_cnt = PJ_ARRAY_SIZE(pjsua_var.thread);

	for (i=0; i<pjsua_var.ua_cfg.thread_cnt; ++i) {
	    status = pj_thread_create(pjsua_var.pool, "pjsua", &worker_thread,
				      NULL, 0, 0, &pjsua_var.thread[i]);
	    if (status != PJ_SUCCESS)
		goto on_error;
	}
	PJ_LOG(4,(THIS_FILE, "%d SIP worker threads created", 
		  pjsua_var.ua_cfg.thread_cnt));
    } else {
	PJ_LOG(4,(THIS_FILE, "No SIP worker threads created"));
    }

    /* Done! */

    PJ_LOG(3,(THIS_FILE, "pjsua version %s for %s initialized", 
			 PJ_VERSION, PJ_OS_NAME));

    return PJ_SUCCESS;

on_error:
    pjsua_destroy();
    return status;
}


/* Sleep with polling */
static void busy_sleep(unsigned msec)
{
#if defined(PJ_SYMBIAN) && PJ_SYMBIAN != 0
    /* Ideally we shouldn't call pj_thread_sleep() and rather
     * CActiveScheduler::WaitForAnyRequest() here, but that will
     * drag in Symbian header and it doesn't look pretty.
     */
    pj_thread_sleep(msec);
#else
    pj_time_val timeout, now;

    pj_gettimeofday(&timeout);
    timeout.msec += msec;
    pj_time_val_normalize(&timeout);

    do {
	while (pjsua_handle_events(10) > 0)
	    ;
	pj_gettimeofday(&now);
    } while (PJ_TIME_VAL_LT(now, timeout));
#endif
}


/*
 * Callback function to receive notification from the resolver
 * when the resolution process completes.
 */
static void stun_dns_srv_resolver_cb(void *user_data,
				     pj_status_t status,
				     const pj_dns_srv_record *rec)
{
    unsigned i;

    PJ_UNUSED_ARG(user_data);

    pjsua_var.stun_status = status;
    
    if (status != PJ_SUCCESS) {
	/* DNS SRV resolution failed. If stun_host is specified, resolve
	 * it with gethostbyname()
	 */
	if (pjsua_var.ua_cfg.stun_host.slen) {
	    pj_str_t str_host, str_port;
	    int port;
	    pj_hostent he;

	    str_port.ptr = pj_strchr(&pjsua_var.ua_cfg.stun_host, ':');
	    if (str_port.ptr != NULL) {
		str_host.ptr = pjsua_var.ua_cfg.stun_host.ptr;
		str_host.slen = (str_port.ptr - str_host.ptr);
		str_port.ptr++;
		str_port.slen = pjsua_var.ua_cfg.stun_host.slen - 
				str_host.slen - 1;
		port = (int)pj_strtoul(&str_port);
		if (port < 1 || port > 65535) {
		    pjsua_perror(THIS_FILE, "Invalid STUN server", PJ_EINVAL);
		    pjsua_var.stun_status = PJ_EINVAL;
		    return;
		}
	    } else {
		str_host = pjsua_var.ua_cfg.stun_host;
		port = 3478;
	    }

	    pjsua_var.stun_status = pj_gethostbyname(&str_host, &he);

	    if (pjsua_var.stun_status == PJ_SUCCESS) {
		pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 0);
		pjsua_var.stun_srv.ipv4.sin_addr = *(pj_in_addr*)he.h_addr;
		pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)port);

		PJ_LOG(3,(THIS_FILE, 
			  "STUN server %.*s resolved, address is %s:%d",
			  (int)pjsua_var.ua_cfg.stun_host.slen,
			  pjsua_var.ua_cfg.stun_host.ptr,
			  pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr),
			  (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port)));
	    }
	} else {
	    char errmsg[PJ_ERR_MSG_SIZE];

	    pj_strerror(status, errmsg, sizeof(errmsg));
	    PJ_LOG(1,(THIS_FILE, 
		     "DNS SRV resolution failed for STUN server %.*s: %s",
		     (int)pjsua_var.ua_cfg.stun_domain.slen,
		     pjsua_var.ua_cfg.stun_domain.ptr,
		     errmsg));
	}
	return;
    }

    pj_memcpy(&pjsua_var.stun_srv, &rec->entry[0].addr, 
	      rec->entry[0].addr_len);

    PJ_LOG(3,(THIS_FILE, "_stun._udp.%.*s resolved, found %d entry(s):",
	      (int)pjsua_var.ua_cfg.stun_domain.slen,
	      pjsua_var.ua_cfg.stun_domain.ptr,
	      rec->count));

    for (i=0; i<rec->count; ++i) {
	PJ_LOG(3,(THIS_FILE, 
		  " %d: prio=%d, weight=%d  %s:%d", 
		  i, rec->entry[i].priority, rec->entry[i].weight,
		  pj_inet_ntoa(rec->entry[i].addr.ipv4.sin_addr),
		  (int)pj_ntohs(rec->entry[i].addr.ipv4.sin_port)));
    }

}

/*
 * Resolve STUN server.
 */
pj_status_t pjsua_resolve_stun_server(pj_bool_t wait)
{
    if (pjsua_var.stun_status == PJ_EUNKNOWN) {
	/* Initialize STUN configuration */
	pj_stun_config_init(&pjsua_var.stun_cfg, &pjsua_var.cp.factory, 0,
			    pjsip_endpt_get_ioqueue(pjsua_var.endpt),
			    pjsip_endpt_get_timer_heap(pjsua_var.endpt));

	/* Start STUN server resolution */
	
	pjsua_var.stun_status = PJ_EPENDING;

	/* If stun_domain is specified, resolve STUN servers with DNS
	 * SRV resolution.
	 */
	if (pjsua_var.ua_cfg.stun_domain.slen) {
	    pj_str_t res_type;
	    pj_status_t status;

	    /* Fail if resolver is not configured */
	    if (pjsua_var.resolver == NULL) {
		PJ_LOG(1,(THIS_FILE, "Nameserver must be configured when "
				     "stun_domain is specified"));
		pjsua_var.stun_status = PJLIB_UTIL_EDNSNONS;
		return PJLIB_UTIL_EDNSNONS;
	    }
	    res_type = pj_str("_stun._udp");
	    status = 
		pj_dns_srv_resolve(&pjsua_var.ua_cfg.stun_domain, &res_type,
				   3478, pjsua_var.pool, pjsua_var.resolver,
				   0, NULL, &stun_dns_srv_resolver_cb);
	    if (status != PJ_SUCCESS) {
		pjsua_perror(THIS_FILE, "Error starting DNS SRV resolution", 
			     pjsua_var.stun_status);
		pjsua_var.stun_status = status;
		return pjsua_var.stun_status;
	    } else {
		pjsua_var.stun_status = PJ_EPENDING;
	    }
	}
	/* Otherwise if stun_host is specified, resolve STUN server with
	 * gethostbyname().
	 */
	else if (pjsua_var.ua_cfg.stun_host.slen) {
	    pj_str_t str_host, str_port;
	    int port;
	    pj_hostent he;

	    str_port.ptr = pj_strchr(&pjsua_var.ua_cfg.stun_host, ':');
	    if (str_port.ptr != NULL) {
		str_host.ptr = pjsua_var.ua_cfg.stun_host.ptr;
		str_host.slen = (str_port.ptr - str_host.ptr);
		str_port.ptr++;
		str_port.slen = pjsua_var.ua_cfg.stun_host.slen - 
				str_host.slen - 1;
		port = (int)pj_strtoul(&str_port);
		if (port < 1 || port > 65535) {
		    pjsua_perror(THIS_FILE, "Invalid STUN server", PJ_EINVAL);
		    pjsua_var.stun_status = PJ_EINVAL;
		    return pjsua_var.stun_status;
		}
	    } else {
		str_host = pjsua_var.ua_cfg.stun_host;
		port = 3478;
	    }


	    pjsua_var.stun_status = pj_gethostbyname(&str_host, &he);

	    if (pjsua_var.stun_status == PJ_SUCCESS) {
		pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 0);
		pjsua_var.stun_srv.ipv4.sin_addr = *(pj_in_addr*)he.h_addr;
		pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)port);

		PJ_LOG(3,(THIS_FILE, 
			  "STUN server %.*s resolved, address is %s:%d",
			  (int)pjsua_var.ua_cfg.stun_host.slen,
			  pjsua_var.ua_cfg.stun_host.ptr,
			  pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr),
			  (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port)));
	    }

	}
	/* Otherwise disable STUN. */
	else {
	    pjsua_var.stun_status = PJ_SUCCESS;
	}


	return pjsua_var.stun_status;

    } else if (pjsua_var.stun_status == PJ_EPENDING) {
	/* STUN server resolution has been started, wait for the
	 * result.
	 */
	if (wait) {
	    while (pjsua_var.stun_status == PJ_EPENDING)
		pjsua_handle_events(10);
	}

	return pjsua_var.stun_status;

    } else {
	/* STUN server has been resolved, return the status */
	return pjsua_var.stun_status;
    }
}

/*
 * Destroy pjsua.
 */
PJ_DEF(pj_status_t) pjsua_destroy(void)
{
    int i;  /* Must be signed */

    /* Signal threads to quit: */
    pjsua_var.thread_quit_flag = 1;

    /* Wait worker threads to quit: */
    for (i=0; i<(int)pjsua_var.ua_cfg.thread_cnt; ++i) {
	if (pjsua_var.thread[i]) {
	    pj_thread_join(pjsua_var.thread[i]);
	    pj_thread_destroy(pjsua_var.thread[i]);
	    pjsua_var.thread[i] = NULL;
	}
    }
    
    if (pjsua_var.endpt) {
	/* Terminate all calls. */
	pjsua_call_hangup_all();

	/* Terminate all presence subscriptions. */
	pjsua_pres_shutdown();

	/* Unregister, if required: */
	for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
	    if (!pjsua_var.acc[i].valid)
		continue;

	    if (pjsua_var.acc[i].regc) {
		pjsua_acc_set_registration(i, PJ_FALSE);
	    }
	}

	/* Wait for some time to allow unregistration to complete: */
	PJ_LOG(4,(THIS_FILE, "Shutting down..."));
	busy_sleep(1000);
    }

    /* Destroy media */
    pjsua_media_subsys_destroy();

    /* Destroy endpoint. */
    if (pjsua_var.endpt) {
	pjsip_endpt_destroy(pjsua_var.endpt);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -