int MRtmpConnection::run()
{
    int ret = E_SUCCESS;

    if ((ret = m_protocol->handshakeWithClient()) != E_SUCCESS) {
        return ret;
    }

    while (!RequestStop) {
        MRtmpMessage *msg = NULL;
        if (m_protocol->recv_message(&msg) != E_SUCCESS)
        {
            log_error("MRtmpConnection recv_message error.");
            break;
        }
        mMSleep(10);
    }

    m_socket->close();
    deleteLater();

    log_trace("MRtmpConnection exit normally.");

    return E_SUCCESS;
}
int BlsHttpClient::sendHttpLiveFlv(const MString &url)
{
    // response http header
    MHttpResponseHeader header;
    header.setStatusLine(200);
    header.addValue("Connection", "close");
    header.addValue("Accept-Ranges", "bytes");
    header.addValue("Cache-Control", "no-store");
    header.setContentType(MHttpHeader::contentType("flv"));

    if (response(header, flv_header, 13) != E_SUCCESS) {
        log_error("response http failed.");
        return -1;
    }

    MRtmpSource *source = MRtmpSource::findSource(url);
    MRtmpPool *pool = new MRtmpPool(url);
    source->addPool(pool);

    while (true) {
        list<MRtmpMessage> msgs = pool->getMessage();
        list<MRtmpMessage>::iterator iter;
        for (iter = msgs.begin(); iter != msgs.end(); ++iter) {
            MRtmpMessage &msg = *iter;

            // to FLV message
            MStream stream = serialFlv(&msg);
            if (m_socket->write(stream) != stream.size()) {
                log_error("send flv tag failed");
                return -2;
            }
        }

        mMSleep(5);
    }

    return E_SUCCESS;
}
int MRtmpConnection::run()
{
    int ret = E_SUCCESS;

    if ((ret = m_protocol->handshakeWithClient()) != E_SUCCESS) {
        return ret;
    }

    while (!RequestStop) {
        MRtmpMessage *msg = NULL;
        int res = m_protocol->recv_message(&msg);
        if (res == E_SOCKET_CLOSE_NORMALLY) {
            break;
        }

        if (res != E_SUCCESS) {
            log_error("MRtmpConnection recv_message error.");
            break;
        }

        mMSleep(10);
    }

    if (m_role == Role_Connection_Publish) {
        MString url = m_protocol->getRtmpCtx()->url();
        g_cchannel->sendLine(Internal_CMD_RemoveHasBackSourceRes, url);
        BlsBackSource::instance()->remove(url);

        log_trace("remove url from master(url=%s)", url.c_str());
    }

    m_socket->close();
    deleteLater();

    log_trace("MRtmpConnection exit normally.");

    return E_SUCCESS;
}
int MRtmpConnection::playService()
{
    int ret = E_SUCCESS;

    MString url = m_protocol->getRtmpCtx()->url();
    MRtmpPool *pool = new MRtmpPool(url, this);
    m_source->addPool(pool);
    while (!RequestStop) {
        list<MRtmpMessage> msgs = pool->getMessage();

        list<MRtmpMessage>::iterator iter;
        for (iter = msgs.begin(); iter != msgs.end(); ++iter) {
            MRtmpMessage &msg = *iter;
            if ((ret = m_protocol->send_message(&msg)) != E_SUCCESS) {
                return ret;
            }
        }

        mMSleep(100);
    }

    return ret;
}
int BlsChild::run()
{
    while (!RequestStop) {
        MString line;
        if (m_socket->readLine(line) != E_SUCCESS) {
            // TODO child exit ? or crash ?
            // should kill child ?
            break;
        }

        if (processCommand(line) != E_SUCCESS) {
            // TODO child exit ? or crash ?
            // should kill child ?
            break;
        }

        mMSleep(100);
    }

    log_trace("BlsChild exit.");
    this->deleteLater();

    return E_SUCCESS;
}
int MRtmpConnection::closeConnection()
{
    mMSleep(500);
    return E_SOCKET_CLOSE_NORMALLY;
}