Пример #1
0
rtmp_live_stream_t* rtmp_app_live_alloc(rtmp_app_t *app,
    const char *livestream)
{
    mem_pool_t              *pool;
    rtmp_live_stream_t      *live;
    uint32_t                 k;
    list_t                  *h;

    if (list_empty(&app->free_lives) == 0) {

        live = struct_entry(app->free_lives.next,
            rtmp_live_stream_t,link);

        list_remove(&live->link);
    } else {
        pool = app->host->cycle->pool;
        live = mem_pcalloc(pool,sizeof(rtmp_live_stream_t));
    }

    if (live) {
        live->epoch = rtmp_current_sec;
        live->timestamp = 0;
        strncpy(live->name,livestream,63);

        live->publisher = NULL;
        live->players = NULL;

        k = rtmp_hash_string(livestream);
        h = app->lives + (k % app->conf->stream_buckets);

        list_insert_head(h,&live->link);
    }

    return live;
}
Пример #2
0
rtmp_app_t* rtmp_create_app(mem_pool_t *pool,rtmp_host_t *host)
{
    mem_pool_t          *chunk_pool;
    rtmp_app_t          *app;
    rtmp_app_conf_t     *conf;
    rtmp_host_conf_t    *hconf;

    hconf = host->hconf;
    app = mem_pcalloc(pool,sizeof(rtmp_app_t) + sizeof(rtmp_app_conf_t));
    if (app == NULL) {
        return NULL;
    }

    chunk_pool = mem_create_pool(MEM_DEFAULT_POOL_SIZE);
    if (chunk_pool == NULL) {
        return NULL;
    }

    conf = (rtmp_app_conf_t*)(app + 1);
    app->conf = conf;
    app->chunk_pool = chunk_pool;

    conf->ack_size = hconf->ack_size;
    conf->ping_timeout = hconf->ping;
    conf->chunk_size = hconf->chunk_size;
    conf->stream_buckets = 1024;

    list_init(&app->free_lives);

    app->host = host;

    return app;
}
Пример #3
0
mem_buf_chain_t* rtmp_core_alloc_chain(rtmp_session_t *session,
    mem_pool_t *pool,int32_t chunk_size)
{
    mem_buf_chain_t *chain;
    uint8_t         *buf;

    chain = mem_alloc_chain_link(pool);
    if (chain) {
        buf = chain->chunk_body;
        if (chain->chunk_size < (uint32_t)chunk_size) {
            buf = NULL;
        }

        if (buf == NULL) {
            buf = mem_pcalloc(pool,chunk_size + RTMP_MAX_CHUNK_HEADER);

            if (buf == NULL) {
                mem_free_chain_link(pool,chain);
                return NULL;
            }

            chain->chunk_body = buf;
            chain->chunk_size = chunk_size;
        }

        chain->chunk.buf  = buf;
        chain->chunk.last = buf;
        chain->chunk.end  = buf + chunk_size + RTMP_MAX_CHUNK_HEADER;
        chain->locked = 1;
        chain->next = NULL;

        rtmp_log(RTMP_LOG_DEBUG,"[%d]alloc chain:%p .buf=%p .last=%p .end=%p",
            session->sid,chain,chain->chunk.buf,
            chain->chunk.last,chain->chunk.end);
    }

    return chain;
}
Пример #4
0
static void *rtmp_host_create_module(rtmp_cycle_t *cycle)
{
    rtmp_hosts_ctx_t *ctx;
    mem_pool_t       *pool;

    pool = cycle->pool;
    ctx = mem_pcalloc(cycle->pool,sizeof(rtmp_hosts_ctx_t));
    if (ctx == NULL) {
        rtmp_log(RTMP_LOG_ERR,"create conf failed");
        return NULL;
    }

    if (array_init(&ctx->server_list,pool,10,sizeof(void *)) != RTMP_OK) {
        rtmp_log(RTMP_LOG_ERR,"create hosts failed");
        return NULL;
    }

    list_init(&ctx->allow_play);
    list_init(&ctx->allow_publish);
    list_init(&ctx->deny_play);
    list_init(&ctx->deny_publish);

    return (void *)ctx;
}
Пример #5
0
rtmp_cycle_t* rtmp_init_cycle(void)
{
    rtmp_cycle_t  *cycle;
    mem_pool_t    *pool,*temp_pool;
    size_t         slen;
    int            m;
    rtmp_module_t *module;

    mem_pagesize = 4096;
    mem_pagesize_shift = 12;
    mem_cacheline_size = 4096;

    pool = mem_create_pool(MEM_DEFAULT_POOL_SIZE);
    if (pool == NULL) {
        rtmp_log(RTMP_LOG_ERR,"alloc pool failed!");
        return NULL;
    }

    temp_pool = mem_create_pool(MEM_DEFAULT_POOL_SIZE);
    if (temp_pool == NULL) {
        rtmp_log(RTMP_LOG_ERR,"alloc temp_pool failed!");
        return NULL;
    }

    slen = strlen(rtmp_conf_file);
    cycle = mem_palloc(pool,sizeof(rtmp_cycle_t));
    if (cycle == NULL) {
        return NULL;
    }

    cycle->pool = pool;
    cycle->temp_pool = temp_pool;

    cycle->conf_file = mem_pcalloc(pool,slen + 1);
    if (cycle->conf_file == NULL) {
        return NULL;
    }
    memcpy(cycle->conf_file,rtmp_conf_file,slen);

    rtmp_max_modules = 0;
    for (m = 0;rtmp_modules[m];m++) {
        rtmp_modules[m]->index = m;
        rtmp_max_modules++;
    }
    cycle->conf = mem_pcalloc(pool,sizeof(void*));

    /*create modules*/
    for (m = 0;rtmp_modules[m];m++) {

        module = rtmp_modules[m];
        if (module->create_module != NULL) {
            module->ctx = module->create_module(cycle);
            if (module->ctx == NULL) {
                rtmp_log(RTMP_LOG_WARNING,"create module failed[%d]",m);
                return NULL;
            }
        }
    }

    if (rtmp_conf_parse(cycle) != RTMP_OK) {
        return NULL;
    }

    for (m = 0;rtmp_modules[m];m++) {

        module = rtmp_modules[m];
        if (module->init_cycle != NULL) {
            if (module->init_cycle(cycle,module) != RTMP_OK) {
                rtmp_log(RTMP_LOG_WARNING,"configure module failed[%d]",m);
                return 0;
            }
        }
    }

    /*init core process*/
    module = rtmp_modules[0];
    if (module->init_forking) {
        if (rtmp_modules[0]->init_forking(cycle,module) == RTMP_FAILED) {
            return 0;
        }
    }

    return cycle;
}
Пример #6
0
static int32_t rtmp_host_init_cycle(rtmp_cycle_t *cycle)
{
    rtmp_hosts_ctx_t *ctx;
    rtmp_conf_t       *conf,*it,*hostc,*appc,*apphead;
    char              *hostname,**word;
    mem_pool_t        *pool;
    rtmp_host_t       *host,**vhost;
    rtmp_app_conf_t  **app;
    rtmp_host_conf_t  *hconf;
    uint32_t           default_server;

    conf = rtmp_get_conf(cycle->conf,"rtmp",GET_CONF_CURRENT);
    if (conf == NULL) {
        return RTMP_FAILED;
    }

    ctx = rtmp_host_moudle.ctx;
    pool = cycle->pool;
    conf = rtmp_get_conf(conf,"server",GET_CONF_CHILD);
    if (conf == NULL) {
        return RTMP_FAILED;
    }

    it = conf;
    do {
        hostc = rtmp_get_conf(it,"server_name",GET_CONF_CHILD);
        default_server = 0;

        hostname = RTMP_HOSTNAME_DEF;
        if (hostc && (hostc->argv.nelts > 1)) {
            word = hostc->argv.elts;

            if ((hostc->argv.nelts > 2) && (strcmp(word[2],"default") == 0)) {
                default_server = 1;
            }

            hostname = word[1];
        }

        if (rtmp_host_conf_find(hostname,& ctx->server_list)) {
            rtmp_log(RTMP_LOG_WARNING,"server [%s] duplicate!",hostname);
            goto next_server;
        }
        
        host = mem_pcalloc(pool,sizeof(rtmp_host_t));
        if (host == NULL) {
            return RTMP_FAILED;
        }

        vhost = array_push(&ctx->server_list);
        if (!vhost) {
            rtmp_log(RTMP_LOG_ERR,"array:no more room!");
            return RTMP_FAILED;
        }
        strncpy(host->name,hostname,sizeof(host->name)-1);

        *vhost = host;

        hconf = mem_pcalloc(pool,sizeof(rtmp_host_conf_t));
        if (hconf == NULL) {
            rtmp_log(RTMP_LOG_ERR,"create host conf failed!");
            return RTMP_FAILED;
        }

        hconf->default_server = default_server;
        host->hconf = hconf;
        
        array_init(& host->apps,pool,10,sizeof(void*));
        
        if (rtmp_host_conf_init(cycle,hostc,host) != RTMP_OK) {
            rtmp_log(RTMP_LOG_ERR,"init host conf failed!");
            return RTMP_FAILED;
        }
        
        appc = rtmp_get_conf(hostc,"app",GET_CONF_NEXT);
        apphead = appc;

        do {
            if (appc == NULL) {
                break;
            }

            app = array_push(& host->apps);
            if (app == NULL) {
                rtmp_log(RTMP_LOG_ERR,"array no more room!");
                return RTMP_FAILED;
            }

            *app = mem_pcalloc(pool,sizeof(rtmp_app_conf_t));
            if (*app == NULL) {
                rtmp_log(RTMP_LOG_ERR,"alloc app failed!");
                return RTMP_FAILED;
            }

            appc = rtmp_get_conf(appc,"app",GET_CONF_NEXT);

            if (appc && appc->argv.nelts > 1) {
                rtmp_app_conf_init(cycle,appc,*app);
            }

        } while (appc != apphead);

    next_server:
        it = rtmp_get_conf(it,"server",GET_CONF_NEXT);
    } while (it && (it != conf));

    return RTMP_OK;
}
Пример #7
0
int32_t rtmp_amf_parse_connect(rtmp_session_t *session,amf_data_t *amf)
{
    char                   *vhost,*ch;
    rtmp_session_connect_t *conn;

    if (session->conn != NULL) {
        rtmp_log(RTMP_LOG_ERR,"[%d]connect app \"%s\" duplicate!",
            session->sid,session->conn->app);
        return RTMP_FAILED;
    }

    conn = mem_pcalloc(session->pool,sizeof(rtmp_session_connect_t));
    if (conn == NULL) {
        rtmp_log(RTMP_LOG_ERR,"[%d]connect app \"%s\" memory failed!",
            session->sid);
        return RTMP_FAILED;
    }

    conn_app_set_string("tcUrl",tc_url,RTMP_CONN_URL_SIZE_MAX);
    conn_app_set_string("app",app,RTMP_CONN_APPNAME_SIZE_MAX);
    conn_app_set_string("pageUrl",page_url,RTMP_CONN_URL_SIZE_MAX);
    conn_app_set_string("swfUrl",swf_url,RTMP_CONN_URL_SIZE_MAX);
    conn_app_set_string("pageUrl",page_url,RTMP_CONN_URL_SIZE_MAX);
    conn_app_set_string("flashVer",flashver,RTMP_CONN_VER_SIZE_MAX);

    if (!conn->app || !conn->tc_url) {
        return RTMP_FAILED;
    }

    conn_app_set_number("audioCodecs",acodecs);
    conn_app_set_number("videoCodecs",vcodecs);
    conn_app_set_number("objectEncoding",object_encoding);

    /*get host*/
    if (memcmp("rtmp://",conn->tc_url,7) != 0) {
        return RTMP_FAILED;
    }

    vhost = mem_dup_str(conn->tc_url+7,session->pool);
    strtok(vhost,":/");

    ch = vhost;
    for (ch = vhost;*ch;ch++) {
        if (*ch == ':' || *ch == '/') {
            *ch = 0;
            break;
        }
    }

    conn->vhost = vhost;
    ch = strchr(conn->app,'?');
    if (ch) {
        *ch++ = 0;
        conn->args = mem_pcalloc(session->pool,RTMP_CONN_ARGS_SIZE_MAX);
        if (conn->args) {
            strncpy(conn->args,ch,RTMP_CONN_ARGS_SIZE_MAX - 1);
        }
    }

    session->conn = conn;
    return RTMP_OK;
}
Пример #8
0
static int32_t rtmp_core_init_process(rtmp_cycle_t *cycle,rtmp_module_t *module)
{
    mem_pool_t         *pool;
    int32_t             conn,i;
    rtmp_connection_t  *next,*c;

    pool = cycle->pool;
    conn = (int32_t)cycle->max_conn;

    cycle->read_events = mem_pcalloc(pool, sizeof(rtmp_event_t)*conn);
    if (cycle->read_events == NULL) {
        return RTMP_FAILED;
    }

    cycle->write_events = mem_pcalloc(pool, sizeof(rtmp_event_t)*conn);
    if (cycle->write_events == NULL) {
        return RTMP_FAILED;
    }

    cycle->connections = mem_pcalloc(pool,
                                     sizeof(rtmp_connection_t) * conn);
    if (cycle->connections == NULL) {
        return RTMP_FAILED;
    }

    c = cycle->connections;
    i = cycle->max_conn;
    next = NULL;

    do {
        i--;

        cycle->write_events[i].write = 1;
        cycle->read_events[i].write = 0;

        c[i].fd = -1;
        c[i].read  = & cycle->read_events[i];
        c[i].write = & cycle->write_events[i];
        c[i].next = next;

        next = & c[i];
    } while (i);

    cycle->free_connections = next;

    /*int message handler*/
    if (rtmp_handler_init(cycle) != RTMP_OK) {
        return RTMP_FAILED;
    }

    /*merge listening*/
    if (rtmp_core_merge_listennings(cycle) != RTMP_OK) {
        return RTMP_FAILED;
    }

    /*open listening*/
    if (rtmp_core_open_listennings(cycle) != RTMP_OK) {
        return RTMP_FAILED;
    }

#if 0
    rtmp_core_dump_listennings(cycle);
    rtmp_core_dump_ports(cycle);
#endif

    return RTMP_OK;
}
Пример #9
0
int32_t rtmp_core_handle_recv(rtmp_session_t *session)
{
    mem_buf_t            *rbuf;
    uint8_t              *payload;
    rtmp_chunk_header_t   hdr;
    rtmp_chunk_stream_t **old_streams;
    rtmp_chunk_stream_t  *st;
    mem_buf_t            *temp_buf;
    size_t                old_size,recv_len,need_len,copy_len;
    int32_t               rc;

    do {
        rbuf = &session->in_chain->chunk;

        /*read chunk head*/
        payload = rtmp_chunk_read(rbuf,&hdr);
        if (payload == 0) {
            return RTMP_OK;
        }

        /*realloc stream ?*/
        if (hdr.csid >= session->max_streams) {

            old_size = session->max_streams * sizeof(rtmp_chunk_stream_t*);
            old_streams = session->chunk_streams;

            session->chunk_streams = mem_pcalloc(session->pool,
                (hdr.csid + 1) * sizeof(rtmp_chunk_stream_t*));
            if (session->chunk_streams == NULL) {
                rtmp_log(RTMP_LOG_ERR,"alloc failed,csid:[%d]",hdr.csid);
                return RTMP_FAILED;
            }

            session->max_streams = hdr.csid + 1;
            memcpy(session->chunk_streams,old_streams,old_size);
        }

        /*get message info*/
        if (rtmp_core_message_info(session,&hdr) != RTMP_OK) {

            rtmp_log(RTMP_LOG_ERR,"[%d] invalid chunk,csid:[%d]",
                session->sid,hdr.csid);
            return RTMP_FAILED;
        }

        st = session->chunk_streams[hdr.csid];
        if (st == NULL) {
            st = mem_pcalloc(session->pool,sizeof(rtmp_chunk_stream_t));
            if (st == NULL) {
                rtmp_log(RTMP_LOG_ERR,"alloc failed,csid:[%d]",hdr.csid);
                return RTMP_FAILED;
            }
            session->chunk_streams[hdr.csid] = st;
        }

        if (st->recvlen == 0) {
            st->hdr = hdr;
        }

        /*an entire chunk ?*/
        recv_len = rbuf->last - payload ;

        if ((recv_len >= session->in_chunk_size)
         || (recv_len + st->recvlen >= st->hdr.msglen))
        {
            if (st->chain == NULL) {
                st->chain = st->last = session->in_chain;
            } else {
                st->last->next = session->in_chain;
                st->last = session->in_chain;
            }

            rtmp_log(RTMP_LOG_DEBUG,"[%d]get a chunk",session->sid);
            rtmp_core_update_chunk_time(session,&hdr);

            session->in_chain = rtmp_core_alloc_chain(session,
                session->c->pool,session->in_chunk_size);

            if (session->in_chain == NULL) {
                rtmp_log(RTMP_LOG_ERR,"[%d]alloc link failed,csid:[%d]",
                    session->sid,hdr.csid);
                return RTMP_FAILED;
            }

            temp_buf = &session->in_chain->chunk;
            need_len = st->hdr.msglen - st->recvlen;

            copy_len = recv_len - rtmp_min(
                rtmp_min(session->in_chunk_size,recv_len),need_len);
            st->recvlen += recv_len - copy_len;
            rbuf->last -= copy_len;

            /*copy left*/
            if (copy_len != 0) {
                memcpy(temp_buf->buf,rbuf->last,copy_len);
                temp_buf->last = temp_buf->buf + copy_len;
            }

            /*remove chunk head*/
            st->last->chunk.buf = payload;

            /*an entire message ?*/
            if (st->recvlen == st->hdr.msglen) {
				/*
				[2015-08-10 14:50:45][info][5][0]get a message:[0]:[20]:[99]
string "connect"
double 1.000000
object: [
[app] : string "live_server"
[type] : string "nonprivate"
[tcUrl] : string "rtmp://localhost/live_server"
[] : ]

				*/
                rtmp_log(RTMP_LOG_INFO,"[%d][%d]get a message:[%d]:[%d]:[%d]",
                    session->sid,session->chunk_time,st->hdr.msgsid,
                    st->hdr.msgtid,st->hdr.msglen);

                st->hdr.chunk_time = session->chunk_time;
                rc = rtmp_core_handle_message(session,&st->hdr,st->chain);

                if (rc != RTMP_OK) {
                    rtmp_log(RTMP_LOG_ERR,"[%d]message (%d)(%d) handler "
                        "failed:[%d]",session->sid,st->hdr.csid,
                        st->hdr.msgtid,rc);

                    return RTMP_FAILED;
                }

                st->recvlen = 0;
                rtmp_core_free_chains(session,session->c->pool,st->chain);
                st->chain = st->last = 0;

                continue;
            }
        }

        break;
    } while (1);

    return RTMP_OK;
}
Пример #10
0
static 
rtmp_conf_t* rtmp_conf_parse_buf(rtmp_conf_buf_t *block, link_t *parent)
{
    mem_pool_t  *pool;
    int          rc;
    link_t      *head,*prev,root;
    rtmp_conf_t *conf,*include,*child;
    char       **word,*file,*p,*start;

    list_init(&root);
    pool = block->pool;

    for (;;) {
    
        conf = mem_pcalloc(pool,sizeof(rtmp_conf_t));
        if (conf == NULL) {
            return NULL;
        }

        list_init(&conf->h);

        array_init(&conf->argv,pool,10,sizeof(char*));
        rc = rtmp_conf_read_token(block,conf);

        switch (rc) {
        case CONF_CONFIG_NEXT:

            conf->v.prev = parent;
            list_insert_tail(&root,&conf->h);

            word = conf->argv.elts;
            if ((conf->argv.nelts > 1) && (strcmp(word[0],"include") == 0)) {

                p = start = block->file;
                while (*start) {
                    if ((*start == '/') || (*start == '\\')) {
                        p = start;
                    }
                    start++;
                }

                if ((*p == '/') || (*p == '\\')) {

                    file = mem_pcalloc(pool,strlen(block->file)+strlen(word[1])+1);
                    if (!file) {
                        return NULL;
                    }

                    memcpy(file,block->file,(p - block->file)+1);
                    strcat(file,word[1]);

                    include = rtmp_conf_parse_file(file,pool,parent);

                } else {

                    include = rtmp_conf_parse_file(word[1],pool,parent);
                }
                
                if (include) {
                    prev = include->h.prev;
                    do {
                        head = prev->next;

                        list_remove(head);
                        list_insert_tail(&root,head);

                    } while (head != prev);
                }
            }

            break;

        case CONF_CONFIG_BLOCK_START:

            conf->v.prev = parent;

            list_insert_tail(&root, &conf->h);
            child = rtmp_conf_parse_buf(block,&conf->v);

            if (child) {
                conf->v.next = &child->v;
            }

            break;

        case CONF_CONFIG_BLOCK_DONE:

            if (&root != root.next) {

                conf = struct_entry(root.next,rtmp_conf_t,h);
                list_remove(&root);

                return conf;
            }

            return NULL;

        case CONF_CONFIG_END:

            if (&root != root.next) {
                conf = struct_entry(root.next,rtmp_conf_t,h);
                list_remove(&root);

                return conf;
            }

            return NULL;

        case CONF_CONFIG_ERROR:
            return NULL;

        default:
            break;
        }
    }

    return NULL;
}