static char * ngx_rtmp_relay_push_pull(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_str_t *value, v, n; ngx_rtmp_relay_app_conf_t *racf; ngx_rtmp_relay_target_t *target, **t; void *addrs; ngx_url_t *u; ngx_uint_t i; ngx_int_t is_pull, is_static; ngx_event_t **ee, *e; ngx_rtmp_relay_static_t *rs; u_char *p; value = cf->args->elts; racf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_relay_module); is_pull = (value[0].data[3] == 'l'); is_static = 0; target = ngx_pcalloc(cf->pool, sizeof(*target)); if (target == NULL) { return NGX_CONF_ERROR; } target->tag = &ngx_rtmp_relay_module; target->data = target; u = &target->url; u->default_port = 1935; u->uri_part = 1; u->url = value[1]; if (ngx_strncasecmp(u->url.data, (u_char *) "rtmp://", 7) == 0) { u->url.data += 7; u->url.len -= 7; } if (ngx_parse_url(cf->pool, u) != NGX_OK) { if (u->err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in url \"%V\"", u->err, &u->url); } return NGX_CONF_ERROR; } value += 2; for (i = 2; i < cf->args->nelts; ++i, ++value) { p = ngx_strlchr(value->data, value->data + value->len, '='); if (p == NULL) { n = *value; ngx_str_set(&v, "1"); } else { n.data = value->data; n.len = p - value->data; v.data = p + 1; v.len = value->data + value->len - p - 1; } #define NGX_RTMP_RELAY_STR_PAR(name, var) \ if (n.len == sizeof(name) - 1 \ && ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \ { \ target->var = v; \ continue; \ } #define NGX_RTMP_RELAY_NUM_PAR(name, var) \ if (n.len == sizeof(name) - 1 \ && ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \ { \ target->var = ngx_atoi(v.data, v.len); \ continue; \ } NGX_RTMP_RELAY_STR_PAR("app", app); NGX_RTMP_RELAY_STR_PAR("name", name); NGX_RTMP_RELAY_STR_PAR("tcUrl", tc_url); NGX_RTMP_RELAY_STR_PAR("pageUrl", page_url); NGX_RTMP_RELAY_STR_PAR("swfUrl", swf_url); NGX_RTMP_RELAY_STR_PAR("flashVer", flash_ver); NGX_RTMP_RELAY_STR_PAR("playPath", play_path); NGX_RTMP_RELAY_NUM_PAR("live", live); NGX_RTMP_RELAY_NUM_PAR("start", start); NGX_RTMP_RELAY_NUM_PAR("stop", stop); #undef NGX_RTMP_RELAY_STR_PAR #undef NGX_RTMP_RELAY_NUM_PAR if (n.len == sizeof("static") - 1 && ngx_strncasecmp(n.data, (u_char *) "static", n.len) == 0 && ngx_atoi(v.data, v.len)) { is_static = 1; continue; } return "unsuppored parameter"; } if (is_static) { if (!is_pull) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "static push is not allowed"); return NGX_CONF_ERROR; } if (target->name.len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "stream name missing in static pull " "declaration"); return NGX_CONF_ERROR; } t = racf->static_pulls.elts; for (i = 0; i < racf->static_pulls.nelts; i++) { if (t[i]->name.len == target->name.len && ngx_strncmp(t[i]->name.data, target->name.data, target->name.len) == 0) { addrs = ngx_palloc(cf->pool, (u->naddrs + t[i]->url.naddrs) * sizeof(ngx_addr_t)); if (addrs == NULL) { return NGX_CONF_ERROR; } ngx_memcpy(addrs, t[i]->url.addrs, t[i]->url.naddrs * sizeof(ngx_addr_t)); ngx_memcpy((char *)addrs + t[i]->url.naddrs * sizeof(ngx_addr_t), u->addrs, u->naddrs * sizeof(ngx_addr_t)); t[i]->url.naddrs += u->naddrs; t[i]->url.addrs = addrs; return NGX_CONF_OK; } } ee = ngx_array_push(&racf->static_events); if (ee == NULL) { return NGX_CONF_ERROR; } e = ngx_pcalloc(cf->pool, sizeof(ngx_event_t)); if (e == NULL) { return NGX_CONF_ERROR; } *ee = e; rs = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_relay_static_t)); if (rs == NULL) { return NGX_CONF_ERROR; } rs->target = target; e->data = rs; e->log = &cf->cycle->new_log; e->handler = ngx_rtmp_relay_static_pull_reconnect; t = ngx_array_push(&racf->static_pulls); } else if (is_pull) { t = ngx_array_push(&racf->pulls); } else { t = ngx_array_push(&racf->pushes); } if (t == NULL) { return NGX_CONF_ERROR; } *t = target; return NGX_CONF_OK; }
static char * ngx_rtmp_relay_push_pull(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_str_t *value, v, n; ngx_rtmp_relay_app_conf_t *racf; ngx_rtmp_relay_target_t *target, **t; ngx_url_t *u; ngx_uint_t i; u_char *p; value = cf->args->elts; racf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_relay_module); t = ngx_array_push(value[0].data[3] == 'h' ? &racf->pushes /* push */ : &racf->pulls /* pull */ ); if (t == NULL) { return NGX_CONF_ERROR; } target = ngx_pcalloc(cf->pool, sizeof(*target)); if (target == NULL) { return NGX_CONF_ERROR; } *t = target; target->tag = &ngx_rtmp_relay_module; target->data = target; u = &target->url; u->default_port = 1935; u->uri_part = 1; u->url = value[1]; if (ngx_strncasecmp(u->url.data, (u_char *) "rtmp://", 7) == 0) { u->url.data += 7; u->url.len -= 7; } if (ngx_parse_url(cf->pool, u) != NGX_OK) { if (u->err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in url \"%V\"", u->err, &u->url); } return NGX_CONF_ERROR; } value += 2; for (i = 2; i < cf->args->nelts; ++i, ++value) { p = ngx_strlchr(value->data, value->data + value->len, '='); if (p == NULL) { return "key=value expected"; } if (p == value->data + value->len - 1) { continue; } n.data = value->data; n.len = p - value->data; v.data = p + 1; v.len = value->data + value->len - p - 1; #define NGX_RTMP_RELAY_STR_PAR(name, var) \ if (n.len == sizeof(#name) - 1 \ && ngx_strncasecmp(n.data, (u_char *)#name, n.len) == 0) \ { \ target->var = v; \ continue; \ } #define NGX_RTMP_RELAY_NUM_PAR(name, var) \ if (n.len == sizeof(#name) - 1 \ && ngx_strncasecmp(n.data, (u_char *)#name, n.len) == 0) \ { \ target->var = ngx_atoi(v.data, v.len); \ continue; \ } NGX_RTMP_RELAY_STR_PAR(app, app); NGX_RTMP_RELAY_STR_PAR(name, name); NGX_RTMP_RELAY_STR_PAR(tcUrl, tc_url); NGX_RTMP_RELAY_STR_PAR(pageUrl, page_url); NGX_RTMP_RELAY_STR_PAR(swfUrl, swf_url); NGX_RTMP_RELAY_STR_PAR(flashVer, flash_ver); NGX_RTMP_RELAY_STR_PAR(playPath, play_path); NGX_RTMP_RELAY_NUM_PAR(live, live); NGX_RTMP_RELAY_NUM_PAR(start, start); NGX_RTMP_RELAY_NUM_PAR(stop, stop); #undef NGX_RTMP_RELAY_STR_PAR #undef NGX_RTMP_RELAY_NUM_PAR return "unsuppored parameter"; } return NGX_CONF_OK; }
ngx_int_t ngx_rtmp_parse_relay_str(ngx_pool_t *pool, ngx_rtmp_relay_target_t *target, u_char *is_static) { ngx_str_t parts, v, n; u_char *b, *m, *e, *last, *dst, *src; parts.len = target->url.uri.len; parts.data = ngx_pstrdup(pool, &target->url.uri); if (parts.data == NULL) { return NGX_ERROR; } last = parts.data + parts.len - 1; b = ngx_strlchr(parts.data, last + 1, '?'); while (b != NULL && ++b < last) { e = ngx_strlchr(b + 1, last + 1, '&'); if (e == NULL) { e = last; } else if (e == b + 1) { b = e + 1; continue; } else { *e = '\0'; e--; } m = ngx_strlchr(b, e + 1, '='); if (m == NULL) { n.data = b; n.len = e - b + 1; ngx_str_set(&v, "1"); } else if (m == e) { n.data = b; n.len = e - b; ngx_str_set(&v, "1"); } else if (m == b) { b = e + 1; continue; } else { n.data = b; n.len = m - b; v.data = m + 1; v.len = e - m; } #define NGX_RTMP_RELAY_STR_PAR(name, var) \ if (n.len == sizeof(name) - 1 \ && ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \ { \ src = v.data; \ dst = ngx_pnalloc(pool, v.len); \ if (dst == NULL) { \ return NGX_ERROR; \ } \ target->var.data = dst; \ ngx_unescape_uri(&dst, &src, v.len, 0); \ target->var.len = dst - target->var.data; \ b = e + 1; \ continue; \ } #define NGX_RTMP_RELAY_NUM_PAR(name, var) \ if (n.len == sizeof(name) - 1 \ && ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \ { \ target->var = ngx_atoi(v.data, v.len); \ b = e + 1; \ continue; \ } NGX_RTMP_RELAY_STR_PAR("app", app); NGX_RTMP_RELAY_STR_PAR("name", name); NGX_RTMP_RELAY_STR_PAR("tcUrl", tc_url); NGX_RTMP_RELAY_STR_PAR("pageUrl", page_url); NGX_RTMP_RELAY_STR_PAR("swfUrl", swf_url); NGX_RTMP_RELAY_STR_PAR("flashVer", flash_ver); NGX_RTMP_RELAY_STR_PAR("playPath", play_path); NGX_RTMP_RELAY_NUM_PAR("live", live); NGX_RTMP_RELAY_NUM_PAR("start", start); NGX_RTMP_RELAY_NUM_PAR("stop", stop); #undef NGX_RTMP_RELAY_STR_PAR #undef NGX_RTMP_RELAY_NUM_PAR if (is_static && n.len == sizeof("static") - 1 && ngx_strncasecmp(n.data, (u_char *) "static", n.len) == 0 && ngx_atoi(v.data, v.len)) { *is_static = 1; continue; } return NGX_ERROR; } return NGX_OK; }