Esempio n. 1
0
pj_status_t create_tcp_listener_transport(int port, pj_str_t& host, pjsip_tpfactory **tcp_factory)
{
  pj_status_t status;
  pj_sockaddr addr;
  pjsip_host_port published_name;
  pjsip_tcp_transport_cfg cfg;

  status = fill_transport_details(port, &addr, host, &published_name);
  if (status != PJ_SUCCESS)
  {
    return status;
  }

  // pjsip_tcp_transport_start2() builds up a configuration structure then calls
  // through to pjsip_tcp_transport_start3().  However it only supports IPv4.
  // Therefore setup the config structure and use pjsip_tcp_transport_start3()
  // instead.

  if (addr.addr.sa_family == PJ_AF_INET)
  {
    pjsip_tcp_transport_cfg_default(&cfg, pj_AF_INET());
  }
  else if (addr.addr.sa_family == PJ_AF_INET6)
  {
    pjsip_tcp_transport_cfg_default(&cfg, pj_AF_INET6());
  }
  else
  {
    status = PJ_EAFNOTSUP;
    CL_SPROUT_SIP_TCP_START_FAIL.log(port,
                                     PJUtils::pj_status_to_string(status).c_str());
    LOG_ERROR("Failed to start TCP transport for port %d  (%s)",
              port,
              PJUtils::pj_status_to_string(status).c_str());
    return status;
  }

  pj_sockaddr_cp(&cfg.bind_addr, &addr);
  pj_memcpy(&cfg.addr_name, &published_name, sizeof(published_name));
  cfg.async_cnt = 50;

  status = pjsip_tcp_transport_start3(stack_data.endpt, &cfg, tcp_factory);

  if (status != PJ_SUCCESS)
  {
    CL_SPROUT_SIP_TCP_SERVICE_START_FAIL.log(port,
                                             PJUtils::pj_status_to_string(status).c_str());
    LOG_ERROR("Failed to start TCP transport for port %d (%s)",
              port,
              PJUtils::pj_status_to_string(status).c_str());
  }

  return status;
}
Esempio n. 2
0
/*
 * This is the public API to create, initialize, register, and start the
 * TCP listener.
 */
PJ_DEF(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt,
					       const pj_sockaddr_in *local,
					       const pjsip_host_port *a_name,
					       unsigned async_cnt,
					       pjsip_tpfactory **p_factory)
{
    pjsip_tcp_transport_cfg cfg;

    pjsip_tcp_transport_cfg_default(&cfg, pj_AF_INET());

    if (local)
	pj_sockaddr_cp(&cfg.bind_addr, local);
    else
	pj_sockaddr_init(cfg.af, &cfg.bind_addr, NULL, 0);

    if (a_name)
	pj_memcpy(&cfg.addr_name, a_name, sizeof(*a_name));

    if (async_cnt)
	cfg.async_cnt = async_cnt;

    return pjsip_tcp_transport_start3(endpt, &cfg, p_factory);
}
Esempio n. 3
0
/*! \brief Apply handler for transports */
static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
{
	struct ast_sip_transport *transport = obj;
	RAII_VAR(struct ast_sip_transport *, existing, ast_sorcery_retrieve_by_id(sorcery, "transport", ast_sorcery_object_get_id(obj)), ao2_cleanup);
	pj_status_t res = -1;

	if (!existing || !existing->state) {
		if (!(transport->state = ao2_alloc(sizeof(*transport->state), transport_state_destroy))) {
			ast_log(LOG_ERROR, "Transport state for '%s' could not be allocated\n", ast_sorcery_object_get_id(obj));
			return -1;
		}
	} else {
		transport->state = existing->state;
		ao2_ref(transport->state, +1);
	}

	/* Once active a transport can not be reconfigured */
	if (transport->state->transport || transport->state->factory) {
		return -1;
	}

	if (transport->host.addr.sa_family != PJ_AF_INET && transport->host.addr.sa_family != PJ_AF_INET6) {
		ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", ast_sorcery_object_get_id(obj));
		return -1;
	}

	/* Set default port if not present */
	if (!pj_sockaddr_get_port(&transport->host)) {
		pj_sockaddr_set_port(&transport->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060);
	}

	/* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */
	if (!ast_strlen_zero(transport->external_signaling_address)) {
		if (transport->host.addr.sa_family == pj_AF_INET()) {
			transport->external_address.ss.ss_family = AF_INET;
		} else if (transport->host.addr.sa_family == pj_AF_INET6()) {
			transport->external_address.ss.ss_family = AF_INET6;
		} else {
			ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n",
					ast_sorcery_object_get_id(obj));
			return -1;
		}

		if (ast_dnsmgr_lookup(transport->external_signaling_address, &transport->external_address, &transport->external_address_refresher, NULL) < 0) {
			ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", ast_sorcery_object_get_id(obj));
			return -1;
		}
	}

	if (transport->type == AST_TRANSPORT_UDP) {
		if (transport->host.addr.sa_family == pj_AF_INET()) {
			res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(), &transport->host.ipv4, NULL, transport->async_operations, &transport->state->transport);
		} else if (transport->host.addr.sa_family == pj_AF_INET6()) {
			res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(), &transport->host.ipv6, NULL, transport->async_operations, &transport->state->transport);
		}

		if (res == PJ_SUCCESS && (transport->tos || transport->cos)) {
			pj_sock_t sock;
			pj_qos_params qos_params;

			sock = pjsip_udp_transport_get_socket(transport->state->transport);
			pj_sock_get_qos_params(sock, &qos_params);
			set_qos(transport, &qos_params);
			pj_sock_set_qos_params(sock, &qos_params);
		}
	} else if (transport->type == AST_TRANSPORT_TCP) {
		pjsip_tcp_transport_cfg cfg;

		pjsip_tcp_transport_cfg_default(&cfg, transport->host.addr.sa_family);
		cfg.bind_addr = transport->host;
		cfg.async_cnt = transport->async_operations;
		set_qos(transport, &cfg.qos_params);

		res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg, &transport->state->factory);
	} else if (transport->type == AST_TRANSPORT_TLS) {
		transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file);
		transport->tls.cert_file = pj_str((char*)transport->cert_file);
		transport->tls.privkey_file = pj_str((char*)transport->privkey_file);
		transport->tls.password = pj_str((char*)transport->password);
		set_qos(transport, &transport->tls.qos_params);

		res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &transport->tls, &transport->host, NULL, transport->async_operations, &transport->state->factory);
	} else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) {
		if (transport->cos || transport->tos) {
			ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n");
		}
		res = PJ_SUCCESS;
	}

	if (res != PJ_SUCCESS) {
		char msg[PJ_ERR_MSG_SIZE];

		pjsip_strerror(res, msg, sizeof(msg));
		ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg);
		return -1;
	}
	return 0;
}
Esempio n. 4
0
/*! \brief Apply handler for transports */
static int transport_apply(const struct ast_sorcery *sorcery, void *obj)
{
	struct ast_sip_transport *transport = obj;
	const char *transport_id = ast_sorcery_object_get_id(obj);
	RAII_VAR(struct ao2_container *, states, transport_states, states_cleanup);
	RAII_VAR(struct internal_state *, temp_state, NULL, ao2_cleanup);
	RAII_VAR(struct internal_state *, perm_state, NULL, ao2_cleanup);
	RAII_VAR(struct ast_variable *, changes, NULL, ast_variables_destroy);
	pj_status_t res = -1;
	int i;
#define BIND_TRIES 3
#define BIND_DELAY_US 100000

	if (!states) {
		return -1;
	}

	/*
	 * transport_apply gets called for EVERY retrieval of a transport when using realtime.
	 * We need to prevent multiple threads from trying to mess with underlying transports
	 * at the same time.  The container is the only thing we have to lock on.
	 */
	ao2_wrlock(states);

	temp_state = internal_state_alloc(transport);
	if (!temp_state) {
		ast_log(LOG_ERROR, "Transport '%s' failed to allocate memory\n", transport_id);
		return -1;
	}

	perm_state = find_internal_state_by_transport(transport);
	if (perm_state) {
		ast_sorcery_diff(sorcery, perm_state->transport, transport, &changes);
		if (!changes && !has_state_changed(perm_state->state, temp_state->state)) {
			/* In case someone is using the deprecated fields, reset them */
			transport->state = perm_state->state;
			copy_state_to_transport(transport);
			ao2_replace(perm_state->transport, transport);
			return 0;
		}

		if (!transport->allow_reload) {
			if (!perm_state->change_detected) {
				perm_state->change_detected = 1;
				ast_log(LOG_WARNING, "Transport '%s' is not reloadable, maintaining previous values\n", transport_id);
			}
			/* In case someone is using the deprecated fields, reset them */
			transport->state = perm_state->state;
			copy_state_to_transport(transport);
			ao2_replace(perm_state->transport, transport);
			return 0;
		}
	}

	if (temp_state->state->host.addr.sa_family != PJ_AF_INET && temp_state->state->host.addr.sa_family != PJ_AF_INET6) {
		ast_log(LOG_ERROR, "Transport '%s' could not be started as binding not specified\n", transport_id);
		return -1;
	}

	/* Set default port if not present */
	if (!pj_sockaddr_get_port(&temp_state->state->host)) {
		pj_sockaddr_set_port(&temp_state->state->host, (transport->type == AST_TRANSPORT_TLS) ? 5061 : 5060);
	}

	/* Now that we know what address family we can set up a dnsmgr refresh for the external media address if present */
	if (!ast_strlen_zero(transport->external_signaling_address)) {
		if (temp_state->state->host.addr.sa_family == pj_AF_INET()) {
			temp_state->state->external_address.ss.ss_family = AF_INET;
		} else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) {
			temp_state->state->external_address.ss.ss_family = AF_INET6;
		} else {
			ast_log(LOG_ERROR, "Unknown address family for transport '%s', could not get external signaling address\n",
					transport_id);
			return -1;
		}

		if (ast_dnsmgr_lookup(transport->external_signaling_address, &temp_state->state->external_address, &temp_state->state->external_address_refresher, NULL) < 0) {
			ast_log(LOG_ERROR, "Could not create dnsmgr for external signaling address on '%s'\n", transport_id);
			return -1;
		}
	}

	if (transport->type == AST_TRANSPORT_UDP) {

		for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) {
			if (perm_state && perm_state->state && perm_state->state->transport) {
				pjsip_udp_transport_pause(perm_state->state->transport,
					PJSIP_UDP_TRANSPORT_DESTROY_SOCKET);
				usleep(BIND_DELAY_US);
			}

			if (temp_state->state->host.addr.sa_family == pj_AF_INET()) {
				res = pjsip_udp_transport_start(ast_sip_get_pjsip_endpoint(),
					&temp_state->state->host.ipv4, NULL, transport->async_operations,
					&temp_state->state->transport);
			} else if (temp_state->state->host.addr.sa_family == pj_AF_INET6()) {
				res = pjsip_udp_transport_start6(ast_sip_get_pjsip_endpoint(),
					&temp_state->state->host.ipv6, NULL, transport->async_operations,
					&temp_state->state->transport);
			}
		}

		if (res == PJ_SUCCESS && (transport->tos || transport->cos)) {
			pj_sock_t sock;
			pj_qos_params qos_params;
			sock = pjsip_udp_transport_get_socket(temp_state->state->transport);
			pj_sock_get_qos_params(sock, &qos_params);
			set_qos(transport, &qos_params);
			pj_sock_set_qos_params(sock, &qos_params);
		}
	} else if (transport->type == AST_TRANSPORT_TCP) {
		pjsip_tcp_transport_cfg cfg;

		pjsip_tcp_transport_cfg_default(&cfg, temp_state->state->host.addr.sa_family);
		cfg.bind_addr = temp_state->state->host;
		cfg.async_cnt = transport->async_operations;
		set_qos(transport, &cfg.qos_params);

		for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) {
			if (perm_state && perm_state->state && perm_state->state->factory
				&& perm_state->state->factory->destroy) {
				perm_state->state->factory->destroy(perm_state->state->factory);
				usleep(BIND_DELAY_US);
			}

			res = pjsip_tcp_transport_start3(ast_sip_get_pjsip_endpoint(), &cfg,
				&temp_state->state->factory);
		}
	} else if (transport->type == AST_TRANSPORT_TLS) {
		if (transport->async_operations > 1 && ast_compare_versions(pj_get_version(), "2.5.0") < 0) {
			ast_log(LOG_ERROR, "Transport: %s: When protocol=tls and pjproject version < 2.5.0, async_operations can't be > 1\n",
					ast_sorcery_object_get_id(obj));
			return -1;
		}

		temp_state->state->tls.password = pj_str((char*)transport->password);
		set_qos(transport, &temp_state->state->tls.qos_params);

		for (i = 0; i < BIND_TRIES && res != PJ_SUCCESS; i++) {
			if (perm_state && perm_state->state && perm_state->state->factory
				&& perm_state->state->factory->destroy) {
				perm_state->state->factory->destroy(perm_state->state->factory);
				usleep(BIND_DELAY_US);
			}

			res = pjsip_tls_transport_start2(ast_sip_get_pjsip_endpoint(), &temp_state->state->tls,
				&temp_state->state->host, NULL, transport->async_operations,
				&temp_state->state->factory);
		}
	} else if ((transport->type == AST_TRANSPORT_WS) || (transport->type == AST_TRANSPORT_WSS)) {
		if (transport->cos || transport->tos) {
			ast_log(LOG_WARNING, "TOS and COS values ignored for websocket transport\n");
		}
		res = PJ_SUCCESS;
	}

	if (res != PJ_SUCCESS) {
		char msg[PJ_ERR_MSG_SIZE];

		pj_strerror(res, msg, sizeof(msg));
		ast_log(LOG_ERROR, "Transport '%s' could not be started: %s\n", ast_sorcery_object_get_id(obj), msg);
		return -1;
	}

	copy_state_to_transport(transport);
	if (perm_state) {
		ao2_unlink_flags(states, perm_state, OBJ_NOLOCK);
	}
	ao2_link_flags(states, temp_state, OBJ_NOLOCK);

	return 0;
}