static void ngx_rtmp_relay_push_reconnect(ngx_event_t *ev) { ngx_rtmp_session_t *s = ev->data; ngx_rtmp_relay_app_conf_t *racf; ngx_rtmp_relay_ctx_t *ctx, *pctx; ngx_uint_t n; ngx_rtmp_relay_target_t *target, **t; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "relay: push reconnect"); racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); if (ctx == NULL) { return; } t = racf->pushes.elts; for (n = 0; n < racf->pushes.nelts; ++n, ++t) { target = *t; if (target->name.len && (ctx->name.len != target->name.len || ngx_memcmp(ctx->name.data, target->name.data, ctx->name.len))) { continue; } for (pctx = ctx->play; pctx; pctx = pctx->next) { if (pctx->tag == &ngx_rtmp_relay_module && pctx->data == target) { break; } } if (pctx) { continue; } if (ngx_rtmp_relay_push(s, &ctx->name, target) == NGX_OK) { continue; } ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "relay: push reconnect failed name='%V' app='%V' " "playpath='%V' url='%V'", &ctx->name, &target->app, &target->play_path, &target->url.url); if (!ctx->push_evt.timer_set) { ngx_add_timer(&ctx->push_evt, racf->push_reconnect); } } }
static ngx_int_t ngx_rtmp_relay_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) { ngx_rtmp_relay_app_conf_t *racf; ngx_rtmp_relay_target_t *target, **t; ngx_str_t name; size_t n; ngx_rtmp_relay_ctx_t *ctx; if (s->auto_pushed) { goto next; } ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); if (ctx && s->relay) { goto next; } racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); if (racf == NULL || racf->pushes.nelts == 0) { goto next; } name.len = ngx_strlen(v->name); name.data = v->name; t = racf->pushes.elts; for (n = 0; n < racf->pushes.nelts; ++n, ++t) { target = *t; if (target->name.len && (name.len != target->name.len || ngx_memcmp(name.data, target->name.data, name.len))) { continue; } if (ngx_rtmp_relay_push(s, &name, target) == NGX_OK) { continue; } ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "relay: push failed name='%V' app='%V' " "playpath='%V' url='%V'", &name, &target->app, &target->play_path, &target->url.url); if (!ctx->push_evt.timer_set) { ngx_add_timer(&ctx->push_evt, racf->push_reconnect); } } next: return next_publish(s, v); }
static ngx_int_t ngx_rtmp_relay_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) { ngx_rtmp_relay_app_conf_t *racf; ngx_rtmp_relay_target_t *target; ngx_str_t name; size_t n; ngx_rtmp_relay_ctx_t *ctx; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); if (ctx && ctx->relay) { goto next; } racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); if (racf == NULL || racf->pushes.nelts == 0) { goto next; } name.len = ngx_strlen(v->name); name.data = v->name; target = racf->pushes.elts; for (n = 0; n < racf->pushes.nelts; ++n, ++target) { if (target->name.len == 0 || (name.len == target->name.len && !ngx_memcmp(name.data, target->name.data, name.len))) { if (ngx_rtmp_relay_push(s, &name, target) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "relay: push failed name='%V' app='%V' " "playpath='%V' url='%V'", &name, &target->app, &target->play_path, &target->url.url); } } } next: return next_publish(s, v); }
static void ngx_rtmp_auto_push_reconnect(ngx_event_t *ev) { ngx_rtmp_session_t *s = ev->data; ngx_rtmp_auto_push_conf_t *apcf; ngx_rtmp_auto_push_ctx_t *ctx; ngx_int_t *slot; ngx_int_t n; ngx_rtmp_relay_target_t at; u_char path[sizeof("unix:") + NGX_MAX_PATH]; u_char flash_ver[sizeof("APSH ,") + NGX_INT_T_LEN * 2]; u_char play_path[NGX_RTMP_MAX_NAME]; ngx_str_t name; u_char *p; ngx_str_t *u; ngx_pid_t pid; ngx_int_t npushed; ngx_core_conf_t *ccf; ngx_file_info_t fi; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "auto_push: reconnect"); apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, ngx_rtmp_auto_push_module); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_module); if (ctx == NULL) { return; } name.data = ctx->name; name.len = ngx_strlen(name.data); ngx_memzero(&at, sizeof(at)); ngx_str_set(&at.page_url, "nginx-auto-push"); at.tag = &ngx_rtmp_auto_push_module; if (ctx->args[0]) { at.play_path.data = play_path; at.play_path.len = ngx_snprintf(play_path, sizeof(play_path), "%s?%s", ctx->name, ctx->args) - play_path; } slot = ctx->slots; npushed = 0; for (n = 0; n < NGX_MAX_PROCESSES; ++n, ++slot) { if (n == ngx_process_slot) { continue; } pid = ngx_processes[n].pid; if (pid == 0 || pid == NGX_INVALID_PID) { continue; } if (*slot) { npushed++; continue; } at.data = &ngx_processes[n]; ngx_memzero(&at.url, sizeof(at.url)); u = &at.url.url; p = ngx_snprintf(path, sizeof(path) - 1, "unix:%V/" NGX_RTMP_AUTO_PUSH_SOCKNAME ".%i", &apcf->socket_dir, n); *p = 0; if (ngx_file_info(path + sizeof("unix:") - 1, &fi) != NGX_OK) { ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "auto_push: " ngx_file_info_n " failed: " "slot=%i pid=%P socket='%s'" "url='%V' name='%s'", n, pid, path, u, ctx->name); continue; } u->data = path; u->len = p - path; if (ngx_parse_url(s->connection->pool, &at.url) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auto_push: auto-push parse_url failed " "url='%V' name='%s'", u, ctx->name); continue; } p = ngx_snprintf(flash_ver, sizeof(flash_ver) - 1, "APSH %i,%i", (ngx_int_t) ngx_process_slot, (ngx_int_t) ngx_pid); at.flash_ver.data = flash_ver; at.flash_ver.len = p - flash_ver; ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "auto_push: connect slot=%i pid=%P socket='%s' name='%s'", n, pid, path, ctx->name); if (ngx_rtmp_relay_push(s, &name, &at) == NGX_OK) { *slot = 1; npushed++; continue; } ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "auto_push: connect failed: slot=%i pid=%P socket='%s'" "url='%V' name='%s'", n, pid, path, u, ctx->name); } ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, ngx_core_module); ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "auto_push: pushed=%i total=%i failed=%i", npushed, ccf->worker_processes, ccf->worker_processes - 1 - npushed); if (ccf->worker_processes == npushed + 1) { return; } /* several workers failed */ slot = ctx->slots; for (n = 0; n < NGX_MAX_PROCESSES; ++n, ++slot) { pid = ngx_processes[n].pid; if (n == ngx_process_slot || *slot == 1 || pid == 0 || pid == NGX_INVALID_PID) { continue; } ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auto_push: connect failed: slot=%i pid=%P name='%s'", n, pid, ctx->name); } if (!ctx->push_evt.timer_set) { ngx_add_timer(&ctx->push_evt, apcf->push_reconnect); } }
static ngx_int_t ngx_rtmp_notify_publish_handle(ngx_rtmp_session_t *s, void *arg, ngx_chain_t *in) { ngx_rtmp_publish_t *v = arg; ngx_int_t rc; ngx_str_t local_name; ngx_rtmp_relay_target_t target; ngx_url_t *u; ngx_rtmp_notify_app_conf_t *nacf; u_char name[NGX_RTMP_MAX_NAME]; static ngx_str_t location = ngx_string("location"); rc = ngx_rtmp_notify_parse_http_retcode(s, in); if (rc == NGX_ERROR) { ngx_rtmp_notify_clear_flag(s, NGX_RTMP_NOTIFY_PUBLISHING); return NGX_ERROR; } if (rc != NGX_AGAIN) { goto next; } /* HTTP 3xx */ ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "notify: publish redirect received"); rc = ngx_rtmp_notify_parse_http_header(s, in, &location, name, sizeof(name) - 1); if (rc <= 0) { goto next; } if (ngx_strncasecmp(name, (u_char *) "rtmp://", 7)) { *ngx_cpymem(v->name, name, rc) = 0; ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "notify: publish redirect to '%s'", v->name); goto next; } /* push */ nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); if (nacf->relay_redirect) { ngx_rtmp_notify_set_name(v->name, NGX_RTMP_MAX_NAME, name, (size_t) rc); } ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "notify: push '%s' to '%*s'", v->name, rc, name); local_name.data = v->name; local_name.len = ngx_strlen(v->name); ngx_memzero(&target, sizeof(target)); u = &target.url; u->url = local_name; u->url.data = name + 7; u->url.len = rc - 7; u->default_port = 1935; u->uri_part = 1; u->no_resolve = 1; /* want ip here */ if (ngx_parse_url(s->connection->pool, u) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "notify: push failed '%V'", &local_name); return NGX_ERROR; } ngx_rtmp_relay_push(s, &local_name, &target); next: return next_publish(s, v); }