int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
{
	int ret = ERROR_SUCCESS;
	
	// forward app
	app = req->app;
	
	stream_name = req->stream;
	server = forward_server;
	std::string s_port = RTMP_DEFAULT_PORT;
	port = ::atoi(RTMP_DEFAULT_PORT);
	
	size_t pos = forward_server.find(":");
	if (pos != std::string::npos) {
		s_port = forward_server.substr(pos + 1);
		server = forward_server.substr(0, pos);
	}
	// discovery vhost
	std::string vhost = req->vhost;
	srs_vhost_resolve(vhost, s_port);
	port = ::atoi(s_port.c_str());
	
	// generate tcUrl
	tc_url = "rtmp://";
	tc_url += vhost;
	tc_url += "/";
	tc_url += req->app;
	
	// dead loop check
	std::string source_ep = req->vhost;
	source_ep += ":";
	source_ep += req->port;
	
	std::string dest_ep = vhost;
	dest_ep += ":";
	dest_ep += s_port;
	
	if (source_ep == dest_ep) {
		ret = ERROR_SYSTEM_FORWARD_LOOP;
		srs_warn("farder loop detected. src=%s, dest=%s, ret=%d", 
			source_ep.c_str(), dest_ep.c_str(), ret);
		return ret;
	}
	srs_trace("start forward %s to %s, stream: %s/%s", 
		source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), 
		stream_name.c_str());
	
	if ((ret = pthread->start()) != ERROR_SUCCESS) {
        srs_error("start srs thread failed. ret=%d", ret);
        return ret;
	}
	
	return ret;
}
int SrsRequest::discovery_app()
{
	int ret = ERROR_SUCCESS;
	
	size_t pos = std::string::npos;
	std::string url = tcUrl;
	
	if ((pos = url.find("://")) != std::string::npos) {
		schema = url.substr(0, pos);
		url = url.substr(schema.length() + 3);
		srs_verbose("discovery schema=%s", schema.c_str());
	}
	
	if ((pos = url.find("/")) != std::string::npos) {
		vhost = url.substr(0, pos);
		url = url.substr(vhost.length() + 1);
		srs_verbose("discovery vhost=%s", vhost.c_str());
	}

	port = RTMP_DEFAULT_PORTS;
	if ((pos = vhost.find(":")) != std::string::npos) {
		port = vhost.substr(pos + 1);
		vhost = vhost.substr(0, pos);
		srs_verbose("discovery vhost=%s, port=%s", vhost.c_str(), port.c_str());
	}
	
	app = url;
	srs_vhost_resolve(vhost, app);
	
	// resolve the vhost from config
	SrsConfDirective* parsed_vhost = config->get_vhost(vhost);
	if (parsed_vhost) {
		vhost = parsed_vhost->arg0();
	}
	
	srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s",
		schema.c_str(), vhost.c_str(), port.c_str(), app.c_str());
	
	if (schema.empty() || vhost.empty() || port.empty() || app.empty()) {
		ret = ERROR_RTMP_REQ_TCURL;
		srs_error("discovery tcUrl failed. "
			"tcUrl=%s, schema=%s, vhost=%s, port=%s, app=%s, ret=%d",
			tcUrl.c_str(), schema.c_str(), vhost.c_str(), port.c_str(), app.c_str(), ret);
		return ret;
	}
	
	strip();
	
	return ret;
}
int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
{
    int ret = ERROR_SUCCESS;
    
    // forward app
    app = req->app;
    
    stream_name = req->stream;
    server = forward_server;
    std::string s_port = RTMP_DEFAULT_PORT;
    port = ::atoi(RTMP_DEFAULT_PORT);
    
    // TODO: FIXME: parse complex params
    size_t pos = forward_server.find(":");
    if (pos != std::string::npos) {
        s_port = forward_server.substr(pos + 1);
        server = forward_server.substr(0, pos);
    }
    // discovery vhost
    std::string vhost = req->vhost;
    srs_vhost_resolve(vhost, s_port);
    port = ::atoi(s_port.c_str());
    
    // generate tcUrl
    tc_url = "rtmp://";
    if (vhost == RTMP_VHOST_DEFAULT) {
        tc_url += forward_server;
    } else {
        tc_url += vhost;
    }
    tc_url += "/";
    tc_url += req->app;
    
    // dead loop check
    std::string source_ep = "rtmp://";
    source_ep += req->host;
    source_ep += ":";
    source_ep += req->port;
    source_ep += "?vhost=";
    source_ep += req->vhost;
    
    std::string dest_ep = "rtmp://";
    if (forward_server == "127.0.0.1") {
        dest_ep += req->host;
    } else {
        dest_ep += forward_server;
    }
    dest_ep += ":";
    dest_ep += s_port;
    dest_ep += "?vhost=";
    dest_ep += vhost;
    
    if (source_ep == dest_ep) {
        ret = ERROR_SYSTEM_FORWARD_LOOP;
        srs_warn("forward loop detected. src=%s, dest=%s, ret=%d", 
            source_ep.c_str(), dest_ep.c_str(), ret);
        return ret;
    }
    srs_trace("start forward %s to %s, tcUrl=%s, stream=%s", 
        source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), 
        stream_name.c_str());
    
    if ((ret = pthread->start()) != ERROR_SUCCESS) {
        srs_error("start srs thread failed. ret=%d", ret);
        return ret;
    }
    srs_trace("forward thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id());
    
    return ret;
}