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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }