static void ngx_syslog_prebuild_header(ngx_syslog_t *task) { size_t len; u_char *p, pid[NGX_INT64_LEN], *appname; ngx_int_t ident_len; appname = (u_char *) NGINX_VAR; p = ngx_snprintf(pid, NGX_INT64_LEN, "%P", ngx_log_pid); len = sizeof(" ") - 1 + ngx_syslog_hostname.len + (task->ident.len == 0 ? (ident_len = sizeof(NGINX_VAR) - 1) : (ident_len = task->ident.len)) + sizeof(" [") - 1 + p - pid + sizeof("]: ") - 1; task->header.len = ngx_min(NGX_SYSLOG_HEADER_LEN, len); ident_len -= ngx_max((ngx_int_t) (len - task->header.len), 0); ngx_snprintf(task->header.data, task->header.len, " %V %*s[%*s]: ", &ngx_syslog_hostname, ident_len, (task->ident.len == 0 ? appname : task->ident.data), p - pid, pid); }
/* This funcion returns pointer to a static buffer */ static void ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path) { ngx_rtmp_record_ctx_t *ctx; ngx_rtmp_record_app_conf_t *rracf; u_char *p, *l; struct tm tm; static u_char buf[NGX_TIME_T_LEN + 1]; static u_char pbuf[NGX_MAX_PATH + 1]; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); rracf = rctx->conf; /* create file path */ p = pbuf; l = pbuf + sizeof(pbuf) - 1; p = ngx_cpymem(p, rracf->path.data, ngx_min(rracf->path.len, (size_t)(l - p - 1))); *p++ = '/'; p = (u_char *)ngx_escape_uri(p, ctx->name, ngx_min(ngx_strlen(ctx->name), (size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT); /* append timestamp */ if (rracf->unique) { p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", rctx->timestamp) - buf, l - p)); } if (ngx_strchr(rracf->suffix.data, '%')) { ngx_libc_localtime(rctx->timestamp, &tm); p += strftime((char *) p, l - p, (char *) rracf->suffix.data, &tm); } else { p = ngx_cpymem(p, rracf->suffix.data, ngx_min(rracf->suffix.len, (size_t)(l - p))); } *p = 0; path->data = pbuf; path->len = p - pbuf; ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V path: '%V'", &rracf->id, path); }
u_char * ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) { ngx_str_t *msg; msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err] : &ngx_unknown_error; size = ngx_min(size, msg->len); return ngx_cpymem(errstr, msg->data, size); }
static void ngx_http_sub_init_tables(ngx_http_sub_tables_t *tables, ngx_http_sub_match_t *match, ngx_uint_t n) { u_char c; ngx_uint_t i, j, min, max, ch; min = match[0].match.len; max = match[0].match.len; for (i = 1; i < n; i++) { min = ngx_min(min, match[i].match.len); max = ngx_max(max, match[i].match.len); } tables->min_match_len = min; tables->max_match_len = max; ngx_http_sub_cmp_index = tables->min_match_len - 1; ngx_sort(match, n, sizeof(ngx_http_sub_match_t), ngx_http_sub_cmp_matches); min = ngx_min(min, 255); ngx_memset(tables->shift, min, 256); ch = 0; for (i = 0; i < n; i++) { for (j = 0; j < min; j++) { c = match[i].match.data[tables->min_match_len - 1 - j]; tables->shift[c] = ngx_min(tables->shift[c], (u_char) j); } c = match[i].match.data[tables->min_match_len - 1]; while (ch <= (ngx_uint_t) c) { tables->index[ch++] = (u_char) i; } } while (ch < 257) { tables->index[ch++] = (u_char) n; } }
void ngx_str_t_2buf(char *buf, ngx_str_t *str) { if(buf == NULL || str == NULL) return; if(str->data != NULL && str->len != 0) { strncpy(buf, (char*)str->data, ngx_min(str->len, NGX_STR2BUF_LEN - 1)); buf[str->len] = '\0'; } }
u_char * ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) //类似strerror 将字符串copy至errstr指向的内存区域,size为errstr限定的长度 { ngx_str_t *msg; msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]: &ngx_unknown_error; size = ngx_min(size, msg->len); return ngx_cpymem(errstr, msg->data, size); }
static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r) { size_t size; ssize_t n; ngx_int_t rc; ngx_buf_t b; u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE]; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http read discarded body"); ngx_memzero(&b, sizeof(ngx_buf_t)); b.temporary = 1; for ( ;; ) { if (r->headers_in.content_length_n == 0) { r->read_event_handler = ngx_http_block_reading; return NGX_OK; } if (!r->connection->read->ready) { return NGX_AGAIN; } size = (size_t) ngx_min(r->headers_in.content_length_n, NGX_HTTP_DISCARD_BUFFER_SIZE); n = r->connection->recv(r->connection, buffer, size); if (n == NGX_ERROR) { r->connection->error = 1; return NGX_OK; } if (n == NGX_AGAIN) { return NGX_AGAIN; } if (n == 0) { return NGX_OK; } b.pos = buffer; b.last = buffer + n; rc = ngx_http_discard_request_body_filter(r, &b); if (rc != NGX_OK) { return rc; } } }
/* This funcion returns pointer to a static buffer */ static u_char * ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, ngx_rtmp_record_node_ctx_t *rctx) { ngx_rtmp_record_ctx_t *ctx; u_char *p, *l; ngx_rtmp_record_node_t *rc; static u_char buf[NGX_TIME_T_LEN + 1]; static u_char path[NGX_MAX_PATH + 1]; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); rc = rctx->conf; /* create file path */ p = path; l = path + sizeof(path) - 1; p = ngx_cpymem(p, rc->path.data, ngx_min(rc->path.len, (size_t)(l - p - 1))); *p++ = '/'; p = (u_char *)ngx_escape_uri(p, ctx->name, ngx_min(ngx_strlen(ctx->name), (size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT); /* append timestamp */ if (rc->unique) { p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", rctx->timestamp) - buf, l - p)); } p = ngx_cpymem(p, rc->suffix.data, ngx_min(rc->suffix.len, (size_t)(l - p))); *p = 0; ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "record: %V path: '%s'", &rc->id, path); return path; }
static void ngx_rtmp_notify_set_name(u_char *dst, size_t dst_len, u_char *src, size_t src_len) { u_char result[16], *p; ngx_md5_t md5; ngx_md5_init(&md5); ngx_md5_update(&md5, src, src_len); ngx_md5_final(result, &md5); p = ngx_hex_dump(dst, result, ngx_min((dst_len - 1) / 2, 16)); *p = '\0'; }
static void ngx_http_replace_script_copy_capture_code(ngx_http_replace_script_engine_t *e) { sre_int_t *cap, from, to, len; u_char *p, *pos; ngx_uint_t n; ngx_chain_t *cl; ngx_http_replace_script_capture_code_t *code; code = (ngx_http_replace_script_capture_code_t *) e->ip; e->ip += sizeof(ngx_http_replace_script_capture_code_t); n = code->n; pos = e->pos; if (n < e->ncaptures) { cap = e->captures; from = cap[n]; to = cap[n + 1]; dd("captures data: %p", e->captures_data); for (cl = e->captures_data; cl; cl = cl->next) { if (from >= cl->buf->file_last) { continue; } /* from < cl->buf->file_last */ if (to <= cl->buf->file_pos) { break; } p = cl->buf->pos + (from - cl->buf->file_pos); len = ngx_min(cl->buf->file_last, to) - from; e->pos = ngx_copy(e->pos, p, len); from += len; } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "replace script capture: \"%*s\"", e->pos - pos, pos); }
static ngx_int_t ngx_rtmp_relay_publish_local(ngx_rtmp_session_t *s) { ngx_rtmp_publish_t v; ngx_rtmp_relay_ctx_t *ctx; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); if (ctx == NULL) { return NGX_ERROR; } ngx_memzero(&v, sizeof(ngx_rtmp_publish_t)); v.silent = 1; *(ngx_cpymem(v.name, ctx->name.data, ngx_min(sizeof(v.name) - 1, ctx->name.len))) = 0; return ngx_rtmp_publish(s, &v); }
int ngx_write_syslog(ngx_syslog_t *task, u_char *buf, size_t len) { size_t l; ngx_int_t n; struct iovec iovs[4]; if (task->fd == -1 && ngx_cached_time->sec >= task->next_try) { ngx_open_log_connection(task); } if (task->fd == -1) { return NGX_ERROR; } if (task->header.len == 0) { ngx_syslog_prebuild_header(task); } iovs[0].iov_base = (void *) task->syslog_pri.data; iovs[0].iov_len = task->syslog_pri.len; l = task->syslog_pri.len; iovs[1].iov_base = (void *) ngx_cached_syslog_time.data; iovs[1].iov_len = ngx_cached_syslog_time.len; l += ngx_cached_syslog_time.len; iovs[2].iov_base = (void *) task->header.data; iovs[2].iov_len = task->header.len; l += task->header.len; iovs[3].iov_base = (void *) buf; iovs[3].iov_len = ngx_min(len, NGX_SYSLOG_MAX_LENGTH - l); n = writev(task->fd, iovs, 4); if (n < 0) { return NGX_ERROR; } return NGX_OK; }
long ngx_tcp_send_data(ngx_tcp_ctx_t *ctx, const u_char *data, int len) { ngx_chain_t *out_chain; size_t data_copyed; ngx_chain_t *cl; ngx_tcp_session_t *s; ngx_connection_t *c; s = ctx->ngx_tcp_session; c = s->connection; out_chain = ngx_tcp_chain_get_free_buf(s->output_ctx, len); if (NULL == out_chain) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "ngx_tcp_send_data|client=%V|out_chain==NULL\n", &c->addr_text); return -1; } data_copyed = 0; for (cl = out_chain; cl; cl = cl->next) { size_t to_copy = cl->buf->end - cl->buf->start; to_copy = ngx_min((len - data_copyed), to_copy); ngx_memcpy(cl->buf->pos, data + data_copyed, to_copy); data_copyed += to_copy; cl->buf->last += to_copy; } if (s->output_buffer_chain == NULL) { s->output_buffer_chain = out_chain; } else { cl = s->output_buffer_chain; while (cl->next != NULL) { cl = cl->next; } cl->next = out_chain; } ctx->pkg_send_count++; ngx_tcp_send(c->write); return 0; }
static size_t ngx_rtmp_hls_chain2buffer(u_char *buffer, size_t size, ngx_chain_t *in, size_t skip) { ngx_buf_t out; out.pos = buffer; out.last = buffer + size - FF_INPUT_BUFFER_PADDING_SIZE; for (; in; in = in->next) { size = in->buf->last - in->buf->pos; if (size < skip) { skip -= size; continue; } out.pos = ngx_cpymem(out.pos, in->buf->pos + skip, ngx_min( size - skip, (size_t)(out.last - out.pos))); skip = 0; } return out.pos - buffer; }
static void ngx_drain_connections(ngx_cycle_t *cycle) { ngx_uint_t i, n; ngx_queue_t *q; ngx_connection_t *c; n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1); for (i = 0; i < n; i++) { if (ngx_queue_empty(&cycle->reusable_connections_queue)) { break; } q = ngx_queue_last(&cycle->reusable_connections_queue); c = ngx_queue_data(q, ngx_connection_t, queue); ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, "reusing connection"); c->close = 1; c->read->handler(c->read); } }
static int ngx_http_lua_socket_udp_receive(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_udp_upstream_t *u; ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; size_t size; int nargs; ngx_http_lua_loc_conf_t *llcf; nargs = lua_gettop(L); if (nargs != 1 && nargs != 2) { return luaL_error(L, "expecting 1 or 2 arguments " "(including the object), but got %d", nargs); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket calling receive() method"); luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); if (u == NULL || u->udp_connection.connection == NULL) { llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_socket_errors) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to receive data on a closed socket: u:%p, " "c:%p", u, u ? u->udp_connection.connection : NULL); } lua_pushnil(L); lua_pushliteral(L, "closed"); return 2; } if (u->ft_type) { u->ft_type = 0; } #if 1 if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; } #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket read timeout: %M", u->read_timeout); size = (size_t) luaL_optnumber(L, 2, UDP_MAX_DATAGRAM_SIZE); size = ngx_min(size, UDP_MAX_DATAGRAM_SIZE); u->recv_buf_size = size; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket receive buffer size: %uz", u->recv_buf_size); rc = ngx_http_lua_socket_udp_read(r, u); if (rc == NGX_ERROR) { dd("read failed: %d", (int) u->ft_type); rc = ngx_http_lua_socket_udp_receive_retval_handler(r, u, L); dd("udp receive retval returned: %d", (int) rc); return rc; } if (rc == NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket receive done in a single run"); return ngx_http_lua_socket_udp_receive_retval_handler(r, u, L); } /* n == NGX_AGAIN */ u->read_event_handler = ngx_http_lua_socket_udp_read_handler; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ctx->cur_co_ctx->cleanup = ngx_http_lua_udp_socket_cleanup; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } else { r->write_event_handler = ngx_http_core_run_phases; } u->co_ctx = ctx->cur_co_ctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_udp_receive_retval_handler; coctx = ctx->cur_co_ctx; coctx->data = u; return lua_yield(L, 0); }
static char * ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { #if (NGX_HAVE_CPU_AFFINITY) ngx_core_conf_t *ccf = conf; u_char ch, *p; ngx_str_t *value; ngx_uint_t i, n; ngx_cpuset_t *mask; if (ccf->cpu_affinity) { return "is duplicate"; } mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(ngx_cpuset_t)); if (mask == NULL) { return NGX_CONF_ERROR; } ccf->cpu_affinity_n = cf->args->nelts - 1; ccf->cpu_affinity = mask; value = cf->args->elts; if (ngx_strcmp(value[1].data, "auto") == 0) { if (cf->args->nelts > 3) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid number of arguments in " "\"worker_cpu_affinity\" directive"); return NGX_CONF_ERROR; } ccf->cpu_affinity_auto = 1; CPU_ZERO(&mask[0]); for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) { CPU_SET(i, &mask[0]); } n = 2; } else { n = 1; } for ( /* void */ ; n < cf->args->nelts; n++) { if (value[n].len > CPU_SETSIZE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"worker_cpu_affinity\" supports up to %d CPUs only", CPU_SETSIZE); return NGX_CONF_ERROR; } i = 0; CPU_ZERO(&mask[n - 1]); for (p = value[n].data + value[n].len - 1; p >= value[n].data; p--) { ch = *p; if (ch == ' ') { continue; } i++; if (ch == '0') { continue; } if (ch == '1') { CPU_SET(i - 1, &mask[n - 1]); continue; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid character \"%c\" in \"worker_cpu_affinity\"", ch); return NGX_CONF_ERROR; } } #else ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "\"worker_cpu_affinity\" is not supported " "on this platform, ignored"); #endif return NGX_CONF_OK; }
static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) { off_t size; ssize_t n; ngx_buf_t *src, *dst; ngx_uint_t sendfile; src = ctx->in->buf; dst = ctx->buf; size = ngx_buf_size(src); size = ngx_min(size, dst->end - dst->pos); sendfile = ctx->sendfile & !ctx->directio; #if (NGX_SENDFILE_LIMIT) if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { sendfile = 0; } #endif if (ngx_buf_in_memory(src)) { ngx_memcpy(dst->pos, src->pos, (size_t) size); src->pos += (size_t) size; dst->last += (size_t) size; if (src->in_file) { if (sendfile) { dst->in_file = 1; dst->file = src->file; dst->file_pos = src->file_pos; dst->file_last = src->file_pos + size; } else { dst->in_file = 0; } src->file_pos += size; } else { dst->in_file = 0; } if (src->pos == src->last) { dst->flush = src->flush; dst->last_buf = src->last_buf; dst->last_in_chain = src->last_in_chain; } } else { #if (NGX_HAVE_ALIGNED_DIRECTIO) if (ctx->unaligned) { if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, ngx_directio_off_n " \"%s\" failed", src->file->name.data); } } #endif #if (NGX_HAVE_FILE_AIO) if (ctx->aio_handler) { n = ngx_file_aio_read(src->file, dst->pos, (size_t) size, src->file_pos, ctx->pool); if (n == NGX_AGAIN) { ctx->aio_handler(ctx, src->file); return NGX_AGAIN; } } else #endif #if (NGX_THREADS) if (src->file->thread_handler) { n = ngx_thread_read(&ctx->thread_task, src->file, dst->pos, (size_t) size, src->file_pos, ctx->pool); if (n == NGX_AGAIN) { ctx->aio = 1; return NGX_AGAIN; } } else #endif { n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos); } #if (NGX_HAVE_ALIGNED_DIRECTIO) if (ctx->unaligned) { ngx_err_t err; err = ngx_errno; if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, ngx_directio_on_n " \"%s\" failed", src->file->name.data); } ngx_set_errno(err); ctx->unaligned = 0; } #endif if (n == NGX_ERROR) { return (ngx_int_t) n; } if (n != size) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, ngx_read_file_n " read only %z of %O from \"%s\"", n, size, src->file->name.data); return NGX_ERROR; } dst->last += n; if (sendfile) { dst->in_file = 1; dst->file = src->file; dst->file_pos = src->file_pos; dst->file_last = src->file_pos + n; } else { dst->in_file = 0; } src->file_pos += n; if (src->file_pos == src->file_last) { dst->flush = src->flush; dst->last_buf = src->last_buf; dst->last_in_chain = src->last_in_chain; } } return NGX_OK; }
static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) { sigset_t set; ngx_int_t n; ngx_uint_t i; struct rlimit rlmt; ngx_core_conf_t *ccf; ngx_listening_t *ls; #if (NGX_HAVE_CPU_AFFINITY) u_char buf[2 * sizeof(CPU_SET_T) + 1]; u_char *p; CPU_SET_T *cpu_affinity; #endif if (ngx_set_environment(cycle, NULL) == NULL) { /* fatal */ exit(2); } ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (worker >= 0 && ccf->priority != 0) { if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setpriority(%d) failed", ccf->priority); } } if (ccf->rlimit_nofile != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile; rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_NOFILE, %i) failed", ccf->rlimit_nofile); } } if (ccf->rlimit_core != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_core; rlmt.rlim_max = (rlim_t) ccf->rlimit_core; if (setrlimit(RLIMIT_CORE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_CORE, %O) failed", ccf->rlimit_core); } } #ifdef RLIMIT_SIGPENDING if (ccf->rlimit_sigpending != NGX_CONF_UNSET) { rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending; rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending; if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setrlimit(RLIMIT_SIGPENDING, %i) failed", ccf->rlimit_sigpending); } } #endif if (geteuid() == 0) { if (setgid(ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setgid(%d) failed", ccf->group); /* fatal */ exit(2); } if (initgroups(ccf->username, ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "initgroups(%s, %d) failed", ccf->username, ccf->group); } if (setuid(ccf->user) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setuid(%d) failed", ccf->user); /* fatal */ exit(2); } } #if (NGX_HAVE_CPU_AFFINITY) if (worker >= 0) { cpu_affinity = ngx_get_cpu_affinity(worker); if (cpu_affinity) { n = ngx_min(sizeof(CPU_SET_T) - 1, 7); for (p = buf; n >= 0; n--) { p = ngx_snprintf(p, 2, "%02Xd", *((u_char *) cpu_affinity + n)); } *p = '\0'; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, ngx_setaffinity_n "(0x%s)", buf); if (ngx_setaffinity(cpu_affinity) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_setaffinity_n "(0x%s) failed", buf); } } } #endif #if (NGX_HAVE_PR_SET_DUMPABLE) /* allow coredump after setuid() in Linux 2.4.x */ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "prctl(PR_SET_DUMPABLE) failed"); } #endif if (ccf->working_directory.len) { if (chdir((char *) ccf->working_directory.data) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "chdir(\"%s\") failed", ccf->working_directory.data); /* fatal */ exit(2); } } sigemptyset(&set); if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } srandom((ngx_pid << 16) ^ ngx_time()); /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].previous = NULL; } for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { /* fatal */ exit(2); } } } for (n = 0; n < ngx_last_process; n++) { if (ngx_processes[n].pid == -1) { continue; } if (n == ngx_process_slot) { continue; } if (ngx_processes[n].channel[1] == -1) { continue; } if (close(ngx_processes[n].channel[1]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } } if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "close() channel failed"); } #if 0 ngx_last_process = 0; #endif if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) == NGX_ERROR) { /* fatal */ exit(2); } }
// if stream's need to continue pull or push chain, otherwise return NGX_OK static ngx_int_t ngx_live_relay_inner_relay(ngx_rtmp_session_t *s, unsigned publishing) { ngx_rtmp_session_t *rs; ngx_live_relay_ctx_t *ctx, *pctx; ngx_live_relay_app_conf_t *lracf; ngx_int_t pslot; pslot = ngx_stream_zone_insert_stream(&s->stream); if (pslot == NGX_ERROR) { // stream zone not configured or configured error ngx_log_error(NGX_LOG_ERR, s->log, 0, "inner relay, insert stream %V failed", &s->stream); return NGX_DECLINED; } ngx_log_error(NGX_LOG_INFO, s->log, 0, "inner relay, stream %V not in current process, " "pslot:%i ngx_process_slot:%i", &s->stream, pslot, ngx_process_slot); s->live_stream->pslot = pslot; if (pslot == ngx_process_slot) { // current process become stream owner return NGX_DECLINED; } rs = ngx_rtmp_create_relay_session(s, &ngx_live_relay_inner_module); if (rs == NULL) { ngx_log_error(NGX_LOG_ERR, s->log, 0, "inner relay, create relay session failed"); return NGX_DECLINED; } rs->publishing = publishing; rs->live_stream = s->live_stream; ngx_live_create_ctx(rs, publishing); ctx = ngx_rtmp_get_module_ctx(rs, ngx_live_relay_module); ctx->reconnect.log = rs->log; ctx->reconnect.data = rs; ctx->reconnect.handler = ngx_live_relay_inner_handler; lracf = ngx_rtmp_get_module_app_conf(rs, ngx_live_relay_module); // play trigger pull or publish trigger push if (s->publishing != rs->publishing) { ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } // normal publisher close, need to trigger pull if (s->publishing && !s->relay) { ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } // reconnect pctx = ngx_rtmp_get_module_ctx(s, ngx_live_relay_module); if (pctx->successd) { // prev relay susccessd ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } if (!pctx->reconnect.timer_set) { // prev relay timeout ctx->failed_reconnect = ngx_min(pctx->failed_reconnect * 2, lracf->relay_reconnect); ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } if (pctx->failed_reconnect) { ctx->failed_reconnect = ngx_min(pctx->failed_reconnect * 2, lracf->relay_reconnect); } else { ctx->failed_reconnect = lracf->failed_reconnect; } ctx->failed_delay = 1; ngx_add_timer(&ctx->reconnect, ctx->failed_reconnect); return NGX_OK; }
static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) { #if OPENSSL_VERSION_NUMBER >= 0x0090707fL const #endif u_char *p; int n; size_t len; time_t now, valid; ngx_str_t response; X509_STORE *store; STACK_OF(X509) *chain; OCSP_CERTID *id; OCSP_RESPONSE *ocsp; OCSP_BASICRESP *basic; ngx_ssl_stapling_t *staple; ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; staple = ctx->data; now = ngx_time(); ocsp = NULL; basic = NULL; id = NULL; if (ctx->code != 200) { goto error; } /* check the response */ len = ctx->response->last - ctx->response->pos; p = ctx->response->pos; ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (ocsp == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "d2i_OCSP_RESPONSE() failed"); goto error; } n = OCSP_response_status(ocsp); if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "OCSP response not successful (%d: %s)", n, OCSP_response_status_str(n)); goto error; } basic = OCSP_response_get1_basic(ocsp); if (basic == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_response_get1_basic() failed"); goto error; } store = SSL_CTX_get_cert_store(staple->ssl_ctx); if (store == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "SSL_CTX_get_cert_store() failed"); goto error; } #if OPENSSL_VERSION_NUMBER >= 0x10001000L SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain); #else chain = staple->ssl_ctx->extra_certs; #endif if (OCSP_basic_verify(basic, chain, store, staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_basic_verify() failed"); goto error; } id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); if (id == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "OCSP_cert_to_id() failed"); goto error; } if (OCSP_resp_find_status(basic, id, &n, NULL, NULL, &thisupdate, &nextupdate) != 1) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status not found in the OCSP response"); goto error; } if (n != V_OCSP_CERTSTATUS_GOOD) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status \"%s\" in the OCSP response", OCSP_cert_status_str(n)); goto error; } if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_check_validity() failed"); goto error; } if (nextupdate) { valid = ngx_ssl_stapling_time(nextupdate); if (valid == (time_t) NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "invalid nextUpdate time in certificate status"); goto error; } } else { valid = NGX_MAX_TIME_T_VALUE; } OCSP_CERTID_free(id); OCSP_BASICRESP_free(basic); OCSP_RESPONSE_free(ocsp); id = NULL; basic = NULL; ocsp = NULL; /* copy the response to memory not in ctx->pool */ response.len = len; response.data = ngx_alloc(response.len, ctx->log); if (response.data == NULL) { goto error; } ngx_memcpy(response.data, ctx->response->pos, response.len); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp response, %s, %uz", OCSP_cert_status_str(n), response.len); if (staple->staple.data) { ngx_free(staple->staple.data); } staple->staple = response; staple->valid = valid; /* * refresh before the response expires, * but not earlier than in 5 minutes, and at least in an hour */ staple->loading = 0; staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); ngx_ssl_ocsp_done(ctx); return; error: staple->loading = 0; staple->refresh = now + 300; if (id) { OCSP_CERTID_free(id); } if (basic) { OCSP_BASICRESP_free(basic); } if (ocsp) { OCSP_RESPONSE_free(ocsp); } ngx_ssl_ocsp_done(ctx); }
static void ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t) { u_char *pos, *pos1; size_t left; ssize_t n; ngx_fd_t fd; ngx_buf_t b; ngx_rtmp_dash_ctx_t *ctx; ngx_rtmp_dash_frag_t *f; static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; if (!t->opened) { return; } ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "dash: close fragment id=%ui, type=%c, pts=%uD", t->id, t->type, t->earliest_pres_time); ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); b.start = buffer; b.end = buffer + sizeof(buffer); b.pos = b.last = b.start; ngx_rtmp_mp4_write_styp(&b); pos = b.last; b.last += 44; /* leave room for sidx */ ngx_rtmp_mp4_write_moof(&b, t->earliest_pres_time, t->sample_count, t->samples, t->sample_mask, t->id); pos1 = b.last; b.last = pos; ngx_rtmp_mp4_write_sidx(&b, t->mdat_size + 8 + (pos1 - (pos + 44)), t->earliest_pres_time, t->latest_pres_time); b.last = pos1; ngx_rtmp_mp4_write_mdat(&b, t->mdat_size + 8); /* move the data down to make room for the headers */ f = ngx_rtmp_dash_get_frag(s, ctx->nfrags); *ngx_sprintf(ctx->stream.data + ctx->stream.len, "%uD.m4%c", f->timestamp, t->type) = 0; fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: error creating dash temp video file"); goto done; } if (ngx_write_fd(fd, b.pos, (size_t) (b.last - b.pos)) == NGX_ERROR) { goto done; } left = (size_t) t->mdat_size; #if (NGX_WIN32) if (SetFilePointer(t->fd, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "dash: SetFilePointer error"); goto done; } #else if (lseek(t->fd, 0, SEEK_SET) == -1) { ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, "dash: lseek error"); goto done; } #endif while (left > 0) { n = ngx_read_fd(t->fd, buffer, ngx_min(sizeof(buffer), left)); if (n == NGX_ERROR) { break; } n = ngx_write_fd(fd, buffer, (size_t) n); if (n == NGX_ERROR) { break; } left -= n; } done: if (fd != NGX_INVALID_FILE) { ngx_close_file(fd); } ngx_close_file(t->fd); t->fd = NGX_INVALID_FILE; t->opened = 0; }
static ngx_int_t ngx_http_limit_req2_lookup(ngx_http_request_t *r, ngx_http_limit_req2_t *limit_req2, ngx_uint_t hash, ngx_uint_t *ep) { u_char *lr_data, *lr_last; size_t lr_vv_len; ngx_int_t rc, excess; ngx_uint_t i; ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_limit_req2_ctx_t *ctx; ngx_http_limit_req2_node_t *lr; ngx_http_variable_value_t *vv; ngx_http_limit_req2_variable_t *lrv; ctx = limit_req2->shm_zone->data; node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; rc = -1; lrv = ctx->limit_vars->elts; while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ lr = (ngx_http_limit_req2_node_t *) &node->color; lr_data = lr->data; lr_last = lr_data + lr->len; for (i = 0; i < ctx->limit_vars->nelts; i++) { vv = ngx_http_get_indexed_variable(r, lrv[i].index); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_req2 vv is %i %v node is %s", lrv[i].index, vv, lr_data); lr_vv_len = ngx_min(lr_last - lr_data, vv->len); if ((rc = ngx_memcmp(vv->data, lr_data, lr_vv_len)) != 0) { break; } if (lr_vv_len != vv->len) { rc = 1; break; } /* lr_vv_len == vv->len */ lr_data += lr_vv_len; } if (rc == 0 && lr_last > lr_data) { rc = -1; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "limit_req2 lookup is : %i, size is %i", rc, ctx->limit_vars->nelts); if (rc == 0) { ngx_queue_remove(&lr->queue); ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ms = (ngx_msec_int_t) (now - lr->last); excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; if (excess < 0) { excess = 0; } *ep = excess; if ((ngx_uint_t) excess > limit_req2->burst) { return NGX_BUSY; } lr->excess = excess; lr->last = now; if (excess) { return NGX_AGAIN; } return NGX_OK; } node = (rc < 0) ? node->left : node->right; } *ep = 0; return NGX_DECLINED; }
static ngx_int_t ngx_live_relay_static_relay(ngx_rtmp_session_t *s, ngx_live_relay_static_relay_t *r) { ngx_rtmp_session_t *rs; ngx_live_relay_ctx_t *ctx, *pctx; ngx_live_relay_app_conf_t *lracf; ngx_live_relay_static_main_conf_t *rsmcf; ngx_live_relay_static_ctx_t *sctx; ngx_live_relay_t *relay; ngx_rtmp_addr_conf_t *addr_conf; relay = r->relay; rsmcf = ngx_rtmp_cycle_get_module_main_conf(ngx_cycle, ngx_live_relay_static_module); addr_conf = ngx_rtmp_find_related_addr_conf((ngx_cycle_t *) ngx_cycle, &rsmcf->pull_port); if (addr_conf == NULL) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "relay static, find related add_conf for %V failed", &rsmcf->pull_port); return NGX_DECLINED; } rs = ngx_rtmp_create_static_session(relay, addr_conf, &ngx_live_relay_static_module); if (rs == NULL) { ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "relay static, create relay session %V failed", &relay->stream); return NGX_DECLINED; } r->session = rs; rs->publishing = 1; rs->live_stream = ngx_live_create_stream(&rs->domain, &rs->stream); ngx_live_create_ctx(rs, 1); sctx = ngx_pcalloc(rs->pool, sizeof(ngx_live_relay_static_ctx_t)); if (sctx == NULL) { ngx_log_error(NGX_LOG_ERR, rs->log, 0, "relay static, create static relay ctx failed"); ngx_rtmp_finalize_session(rs); return NGX_OK; } ngx_rtmp_set_ctx(rs, sctx, ngx_live_relay_static_module); sctx->relay = r; ctx = ngx_rtmp_get_module_ctx(rs, ngx_live_relay_module); ctx->reconnect.log = rs->log; ctx->reconnect.data = rs; ctx->reconnect.handler = ngx_live_relay_static_handler; if (s == NULL) { ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } // reconnect pctx = ngx_rtmp_get_module_ctx(s, ngx_live_relay_module); if (pctx->successd) { // prev relay successd ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } ctx->idx = pctx->idx; ctx->failed_reconnect = pctx->failed_reconnect; if (ctx->idx < relay->urls.nelts) { // retry backup url immediately ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } lracf = ngx_rtmp_get_module_app_conf(rs, ngx_live_relay_module); if (!pctx->reconnect.timer_set) { // prev relay timeout ctx->failed_reconnect = ngx_min(pctx->failed_reconnect * 2, lracf->relay_reconnect); ngx_post_event(&ctx->reconnect, &ngx_posted_events); return NGX_OK; } if (pctx->failed_reconnect) { ctx->failed_reconnect = ngx_min(pctx->failed_reconnect * 2, lracf->relay_reconnect); } else { ctx->failed_reconnect = lracf->failed_reconnect; } ctx->failed_delay = 1; ngx_add_timer(&ctx->reconnect, ctx->failed_reconnect); return NGX_OK; }
static ngx_int_t ngx_live_relay_httpflv_parse(ngx_rtmp_session_t *s, ngx_buf_t *b) { u_char ch, *p, *pc; ngx_rtmp_stream_t *st; ngx_rtmp_header_t *h; ngx_chain_t **ll; size_t len; ngx_rtmp_core_srv_conf_t *cscf; ngx_int_t rc = NGX_AGAIN; enum { flv_header_F = 0, flv_header_FL, flv_header_FLV, flv_header_Version, flv_header_Flags, flv_header_DataOffset0, flv_header_DataOffset1, flv_header_DataOffset2, flv_header_DataOffset3, flv_tagsize0, flv_tagsize1, flv_tagsize2, flv_tagsize3, flv_tagtype, flv_datasize0, flv_datasize1, flv_datasize2, flv_timestamp0, flv_timestamp1, flv_timestamp2, flv_timestamp_extended, flv_streamid0, flv_streamid1, flv_streamid2, flv_data } state; state = s->flv_state; cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); for (p = b->pos; p < b->last; ++p) { ch = *p; switch (state) { case flv_header_F: switch (ch) { case 'F': state = flv_header_FL; break; default: rc = NGX_ERROR; goto done; } break; case flv_header_FL: switch (ch) { case 'L': state = flv_header_FLV; break; default: rc = NGX_ERROR; goto done; } break; case flv_header_FLV: switch (ch) { case 'V': state = flv_header_Version; break; default: rc = NGX_ERROR; goto done; } break; case flv_header_Version: s->flv_version = ch; if (s->flv_version != 1) { rc = NGX_ERROR; goto done; } state = flv_header_Flags; break; case flv_header_Flags: s->flv_flags = ch; state = flv_header_DataOffset0; break; case flv_header_DataOffset0: pc = (u_char *) &s->flv_data_offset; pc[3] = ch; state = flv_header_DataOffset1; break; case flv_header_DataOffset1: pc = (u_char *) &s->flv_data_offset; pc[2] = ch; state = flv_header_DataOffset2; break; case flv_header_DataOffset2: pc = (u_char *) &s->flv_data_offset; pc[1] = ch; state = flv_header_DataOffset3; break; case flv_header_DataOffset3: pc = (u_char *) &s->flv_data_offset; pc[0] = ch; state = flv_tagsize0; break; case flv_tagsize0: s->flv_tagsize = 0; pc = (u_char *) &s->flv_tagsize; pc[3] = ch; state = flv_tagsize1; break; case flv_tagsize1: pc = (u_char *) &s->flv_tagsize; pc[2] = ch; state = flv_tagsize2; break; case flv_tagsize2: pc = (u_char *) &s->flv_tagsize; pc[1] = ch; state = flv_tagsize3; break; case flv_tagsize3: pc = (u_char *) &s->flv_tagsize; pc[0] = ch; st = &s->in_streams[0]; h = &st->hdr; if (h->mlen == 0 && s->flv_first_pts == 0) { s->flv_first_pts = 1; if (s->flv_tagsize != 0) { rc = NGX_ERROR; goto done; } } else { if (h->mlen + 11 != s->flv_tagsize) { rc = NGX_ERROR; goto done; } } state = flv_tagtype; break; case flv_tagtype: if (ch != NGX_RTMP_MSG_AMF_META && ch != NGX_RTMP_MSG_AUDIO && ch != NGX_RTMP_MSG_VIDEO) { rc = NGX_ERROR; goto done; } st = &s->in_streams[0]; h = &st->hdr; h->type = ch; state = flv_datasize0; break; case flv_datasize0: st = &s->in_streams[0]; h = &st->hdr; h->mlen = 0; pc = (u_char *) &h->mlen; pc[2] = ch; state = flv_datasize1; break; case flv_datasize1: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->mlen; pc[1] = ch; state = flv_datasize2; break; case flv_datasize2: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->mlen; pc[0] = ch; state = flv_timestamp0; st->len = h->mlen; break; case flv_timestamp0: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->timestamp; pc[2] = ch; state = flv_timestamp1; break; case flv_timestamp1: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->timestamp; pc[1] = ch; state = flv_timestamp2; break; case flv_timestamp2: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->timestamp; pc[0] = ch; state = flv_timestamp_extended; break; case flv_timestamp_extended: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->timestamp; pc[3] = ch; state = flv_streamid0; break; case flv_streamid0: st = &s->in_streams[0]; h = &st->hdr; h->msid = 0; pc = (u_char *) &h->msid; pc[2] = ch; state = flv_streamid1; break; case flv_streamid1: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->msid; pc[1] = ch; state = flv_streamid2; break; case flv_streamid2: st = &s->in_streams[0]; h = &st->hdr; pc = (u_char *) &h->msid; pc[0] = ch; state = flv_data; break; case flv_data: st = &s->in_streams[0]; for (ll = &st->in; (*ll) && (*ll)->buf->last == (*ll)->buf->end; ll = &(*ll)->next); for (;;) { if (*ll == NULL) { *ll = ngx_get_chainbuf(cscf->chunk_size, 1); } len = ngx_min(st->len, b->last - p); if ((*ll)->buf->end - (*ll)->buf->last >= (long) len) { (*ll)->buf->last = ngx_cpymem((*ll)->buf->last, p, len); p += len; st->len -= len; break; } len = (*ll)->buf->end - (*ll)->buf->last; (*ll)->buf->last = ngx_cpymem((*ll)->buf->last, p, len); p += len; st->len -= len; ll = &(*ll)->next; } if (st->len != 0) { rc = NGX_AGAIN; goto done; } state = flv_tagsize0; rc = NGX_OK; goto done; } } done: b->pos = p; s->flv_state = state; return rc; }
static ngx_int_t ngx_http_tnt_send_reply(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_http_tnt_ctx_t *ctx) { tp_transcode_t tc; ngx_int_t rc; ngx_http_tnt_loc_conf_t *tlcf; ngx_buf_t *output; size_t output_size; tlcf = ngx_http_get_module_loc_conf(r, ngx_http_tnt_module); output_size = (ctx->tp_cache->end - ctx->tp_cache->start + ngx_http_tnt_overhead()) * tlcf->out_multiplier; output = ngx_http_tnt_create_mem_buf(r, u, output_size); if (output == NULL) { return NGX_ERROR; } if (ctx->batch_size > 0 && ctx->rest_batch_size == ctx->batch_size) { *output->pos = '['; ++output->pos; } tp_transcode_init_args_t args = { .output = (char *)output->pos, .output_size = output->end - output->pos, .method = NULL, .method_len = 0, .codec = TP_REPLY_TO_JSON, .mf = NULL }; rc = tp_transcode_init(&tc, &args); if (rc == TP_TRANSCODE_ERROR) { crit("[BUG] failed to call tp_transcode_init(output)"); return NGX_ERROR; } rc = tp_transcode(&tc, (char *)ctx->tp_cache->start, ctx->tp_cache->end - ctx->tp_cache->start); if (rc == TP_TRANSCODE_OK) { size_t complete_msg_size = 0; rc = tp_transcode_complete(&tc, &complete_msg_size); if (rc == TP_TRANSCODE_ERROR) { crit("[BUG] failed to complete output transcoding"); ngx_pfree(r->pool, output); const ngx_http_tnt_error_t *e = get_error_text(UNKNOWN_PARSE_ERROR); output = ngx_http_tnt_set_err(r, e->code, e->msg.data, e->msg.len); if (output == NULL) { goto error_exit; } goto done; } output->last = output->pos + complete_msg_size; } else if (rc == TP_TRANSCODE_ERROR) { crit("[BUG] failed to transcode output, err: '%s'", tc.errmsg); ngx_pfree(r->pool, output); output = ngx_http_tnt_set_err(r, tc.errcode, (u_char *)tc.errmsg, ngx_strlen(tc.errmsg)); if (output == NULL) { goto error_exit; } } done: tp_transcode_free(&tc); if (ctx->batch_size > 0) { if (ctx->rest_batch_size == 1) { *output->last = ']'; ++output->last; } else if (ctx->rest_batch_size <= ctx->batch_size) { *output->last = ','; ++output->last; } } return ngx_http_tnt_output(r, u, output); error_exit: tp_transcode_free(&tc); return NGX_ERROR; } static ngx_int_t ngx_http_tnt_filter_reply(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_buf_t *b) { ngx_http_tnt_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_tnt_module); ssize_t bytes = b->last - b->pos; dd("filter_reply -> recv bytes: %i, rest: %i", (int)bytes, (int)ctx->rest); if (ctx->state == READ_PAYLOAD) { ssize_t payload_rest = ngx_min(ctx->payload.e - ctx->payload.p, bytes); if (payload_rest > 0) { ctx->payload.p = ngx_copy(ctx->payload.p, b->pos, payload_rest); bytes -= payload_rest; b->pos += payload_rest; payload_rest = ctx->payload.e - ctx->payload.p; dd("filter_reply -> payload rest:%i", (int)payload_rest); } if (payload_rest == 0) { ctx->payload_size = tp_read_payload((char *)&ctx->payload.mem[0], (char *)ctx->payload.e); if (ctx->payload_size <= 0) { crit("[BUG] tp_read_payload failed, ret:%i", (int)ctx->payload_size); return NGX_ERROR; } ctx->rest = ctx->payload_size - 5 /* - header size */; dd("filter_reply -> got header payload:%i, rest:%i", (int)ctx->payload_size, (int)ctx->rest); ctx->tp_cache = ngx_create_temp_buf(r->pool, ctx->payload_size); if (ctx->tp_cache == NULL) { return NGX_ERROR; } ctx->tp_cache->pos = ctx->tp_cache->start; ctx->tp_cache->memory = 1; ctx->tp_cache->pos = ngx_copy(ctx->tp_cache->pos, &ctx->payload.mem[0], sizeof(ctx->payload.mem) - 1); ctx->payload.p = &ctx->payload.mem[0]; ctx->state = READ_BODY; } else { return NGX_OK; } } ngx_int_t rc = NGX_OK; if (ctx->state == READ_BODY) { ssize_t rest = ctx->rest - bytes, read_on = bytes; if (rest < 0) { rest *= -1; read_on = bytes - rest; ctx->rest = 0; ctx->state = SEND_REPLY; rc = NGX_AGAIN; } else if (rest == 0) { ctx->state = SEND_REPLY; ctx->rest = 0; } else { ctx->rest -= bytes; } ctx->tp_cache->pos = ngx_copy(ctx->tp_cache->pos, b->pos, read_on); b->pos += read_on; dd("filter_reply -> read_on:%i, rest:%i, cache rest:%i, buf size:%i", (int)read_on, (int)ctx->rest, (int)(ctx->tp_cache->end - ctx->tp_cache->pos), (int)(b->last - b->pos)); } if (ctx->state == SEND_REPLY) { rc = ngx_http_tnt_send_reply(r, u, ctx); ctx->state = READ_PAYLOAD; ctx->rest = ctx->payload_size = 0; --ctx->rest_batch_size; if (ctx->rest_batch_size <= 0) { u->length = 0; ctx->rest_batch_size = 0; ctx->batch_size = 0; } ngx_pfree(r->pool, ctx->tp_cache); ctx->tp_cache = NULL; if (b->last - b->pos > 0) { rc = NGX_AGAIN; } } return rc; }
ngx_http_reqstat_rbnode_t * ngx_http_reqstat_rbtree_lookup(ngx_shm_zone_t *shm_zone, ngx_str_t *val) { size_t size, len; uint32_t hash; ngx_int_t rc, excess; ngx_time_t *tp; ngx_msec_t now; ngx_queue_t *q; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_reqstat_ctx_t *ctx; ngx_http_reqstat_rbnode_t *rs; ctx = shm_zone->data; hash = ngx_murmur_hash2(val->data, val->len); node = ctx->sh->rbtree.root; sentinel = ctx->sh->rbtree.sentinel; tp = ngx_timeofday(); now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); ngx_shmtx_lock(&ctx->shpool->mutex); while (node != sentinel) { if (hash < node->key) { node = node->left; continue; } if (hash > node->key) { node = node->right; continue; } /* hash == node->key */ rs = (ngx_http_reqstat_rbnode_t *) &node->color; /* len < node->len */ if (val->len < (size_t) rs->len) { node = node->left; continue; } rc = ngx_strncmp(val->data, rs->data, (size_t) rs->len); if (rc == 0) { ms = (ngx_msec_int_t) (now - rs->last_visit); rs->excess = rs->excess - ngx_abs(ms) * ctx->recycle_rate / 1000 + 1000; rs->last_visit = now; if (rs->excess > 0) { ngx_queue_remove(&rs->visit); ngx_queue_insert_head(&ctx->sh->visit, &rs->visit); } ngx_log_debug2(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup exist: %*s", rs->len, rs->data); ngx_shmtx_unlock(&ctx->shpool->mutex); return rs; } node = (rc < 0) ? node->left : node->right; } rc = 0; node = NULL; size = offsetof(ngx_rbtree_node_t, color) + offsetof(ngx_http_reqstat_rbnode_t, data) + ctx->key_len; if (ctx->alloc_already_fail == 0) { node = ngx_slab_alloc_locked(ctx->shpool, size); if (node == NULL) { ctx->alloc_already_fail = 1; } } if (node == NULL) { /* try to free a vacant node */ q = ngx_queue_last(&ctx->sh->visit); rs = ngx_queue_data(q, ngx_http_reqstat_rbnode_t, visit); ms = (ngx_msec_int_t) (now - rs->last_visit); excess = rs->excess - ngx_abs(ms) * ctx->recycle_rate / 1000; ngx_log_debug3(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup try recycle: %*s, %d", rs->len, rs->data, excess); if (excess < 0) { rc = 1; node = (ngx_rbtree_node_t *) ((char *) rs - offsetof(ngx_rbtree_node_t, color)); ngx_rbtree_delete(&ctx->sh->rbtree, node); ngx_queue_remove(&rs->visit); ngx_log_debug2(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup recycle: %*s", rs->len, rs->data); rs->conn_total = 0; ngx_memzero((void *) &rs->bytes_in, size - offsetof(ngx_rbtree_node_t, color) - offsetof(ngx_http_reqstat_rbnode_t, bytes_in)); } else { ngx_shmtx_unlock(&ctx->shpool->mutex); return NULL; } } node->key = hash; rs = (ngx_http_reqstat_rbnode_t *) &node->color; len = ngx_min(ctx->key_len, (ssize_t) val->len); ngx_memcpy(rs->data, val->data, len); rs->len = len; ngx_rbtree_insert(&ctx->sh->rbtree, node); ngx_queue_insert_head(&ctx->sh->visit, &rs->visit); if (!rc) { ngx_queue_insert_head(&ctx->sh->queue, &rs->queue); } rs->last_visit = now; rs->excess = 1000; ngx_log_debug2(NGX_LOG_DEBUG_CORE, shm_zone->shm.log, 0, "reqstat lookup build: %*s", rs->len, rs->data); ngx_shmtx_unlock(&ctx->shpool->mutex); return rs; }
static ngx_int_t ngx_http_slice_header_filter(ngx_http_request_t *r) { off_t end; ngx_int_t rc; ngx_table_elt_t *h; ngx_http_slice_ctx_t *ctx; ngx_http_slice_loc_conf_t *slcf; ngx_http_slice_content_range_t cr; ctx = ngx_http_get_module_ctx(r, ngx_http_slice_filter_module); if (ctx == NULL) { return ngx_http_next_header_filter(r); } if (r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT) { if (r == r->main) { ngx_http_set_ctx(r, NULL, ngx_http_slice_filter_module); return ngx_http_next_header_filter(r); } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unexpected status code %ui in slice response", r->headers_out.status); return NGX_ERROR; } h = r->headers_out.etag; if (ctx->etag.len) { if (h == NULL || h->value.len != ctx->etag.len || ngx_strncmp(h->value.data, ctx->etag.data, ctx->etag.len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "etag mismatch in slice response"); return NGX_ERROR; } } if (h) { ctx->etag = h->value; } if (ngx_http_slice_parse_content_range(r, &cr) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid range in slice response"); return NGX_ERROR; } if (cr.complete_length == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no complete length in slice response"); return NGX_ERROR; } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http slice response range: %O-%O/%O", cr.start, cr.end, cr.complete_length); slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_filter_module); end = ngx_min(cr.start + (off_t) slcf->size, cr.complete_length); if (cr.start != ctx->start || cr.end != end) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unexpected range in slice response: %O-%O", cr.start, cr.end); return NGX_ERROR; } ctx->start = end; r->headers_out.status = NGX_HTTP_OK; r->headers_out.status_line.len = 0; r->headers_out.content_length_n = cr.complete_length; r->headers_out.content_offset = cr.start; r->headers_out.content_range->hash = 0; r->headers_out.content_range = NULL; r->allow_ranges = 1; r->subrequest_ranges = 1; r->single_range = 1; rc = ngx_http_next_header_filter(r); if (r != r->main) { return rc; } if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) { if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) { ctx->start = slcf->size * (r->headers_out.content_offset / slcf->size); } ctx->end = r->headers_out.content_offset + r->headers_out.content_length_n; } else { ctx->end = cr.complete_length; } return rc; }
static ngx_int_t ngx_http_tfs_parse_read_meta_message(ngx_http_tfs_t *t) { u_char *p; int64_t curr_length; uint16_t type; uint32_t count; uint64_t end_offset; ngx_int_t i, rc; ngx_str_t action; ngx_http_tfs_header_t *header; ngx_http_tfs_segment_data_t *first_segment, *last_segment, *segment_data; ngx_http_tfs_file_hole_info_t *file_hole_info; ngx_http_tfs_peer_connection_t *tp; ngx_http_tfs_ms_read_response_t *resp; ngx_http_tfs_meta_frag_meta_info_t *fmi; header = (ngx_http_tfs_header_t *) t->header; tp = t->tfs_peer; type = header->type; switch (type) { case NGX_HTTP_TFS_STATUS_MESSAGE: ngx_str_set(&action, "read file(meta server)"); return ngx_http_tfs_status_message(&tp->body_buffer, &action, t->log); } resp = (ngx_http_tfs_ms_read_response_t *) tp->body_buffer.pos; count = resp->frag_info.frag_count & ~(1 << (sizeof(uint32_t) * 8 - 1)); t->file.cluster_id = resp->frag_info.cluster_id; if (t->r_ctx.action.code == NGX_HTTP_TFS_ACTION_WRITE_FILE) { return NGX_OK; } if (count == 0) { return NGX_DECLINED; } if (t->file.segment_data == NULL) { t->file.segment_data = ngx_pcalloc(t->pool, sizeof(ngx_http_tfs_segment_data_t) * count); if (t->file.segment_data == NULL) { return NGX_ERROR; } /* the first semgent offset is special for pread */ t->is_first_segment = NGX_HTTP_TFS_YES; } else { /* need realloc */ if (count > t->file.segment_count) { t->file.segment_data = ngx_http_tfs_prealloc(t->pool, t->file.segment_data, sizeof(ngx_http_tfs_segment_data_t) * t->file.segment_count, sizeof(ngx_http_tfs_segment_data_t) * count); if (t->file.segment_data == NULL) { return NGX_ERROR; } } /* reuse */ ngx_memzero(t->file.segment_data, sizeof(ngx_http_tfs_segment_data_t) * count); } t->file.segment_count = count; t->file.still_have = resp->still_have ? :t->has_split_frag; t->file.segment_index = 0; p = tp->body_buffer.pos + sizeof(ngx_http_tfs_ms_read_response_t); fmi = (ngx_http_tfs_meta_frag_meta_info_t *) p; curr_length = 0; for (i = 0; i < count; i++, fmi++) { t->file.segment_data[i].segment_info.block_id = fmi->block_id; t->file.segment_data[i].segment_info.file_id = fmi->file_id; t->file.segment_data[i].segment_info.offset = fmi->offset; t->file.segment_data[i].segment_info.size = fmi->size; t->file.segment_data[i].oper_size = fmi->size; } /* the first semgent's oper_offset and oper_size are special for pread */ if (t->r_ctx.action.code == NGX_HTTP_TFS_ACTION_READ_FILE) { first_segment = &t->file.segment_data[0]; if (t->is_first_segment) { /* skip file hole */ first_segment->oper_offset = ngx_max(t->r_ctx.offset, first_segment->segment_info.offset); if (first_segment->segment_info.offset > 0) { first_segment->oper_offset %= first_segment->segment_info.offset; } first_segment->oper_size = first_segment->segment_info.size - first_segment->oper_offset; t->is_first_segment = NGX_HTTP_TFS_NO; if (t->r_ctx.chk_file_hole) { rc = ngx_array_init(&t->file_holes, t->pool, NGX_HTTP_TFS_INIT_FILE_HOLE_COUNT, sizeof(ngx_http_tfs_file_hole_info_t)); if (rc == NGX_ERROR) { return NGX_ERROR; } } } /* last segment(also special) has been readed, set its oper_size*/ /* notice that it maybe the same as first_segment */ if (!t->file.still_have) { last_segment = &t->file.segment_data[count - 1]; end_offset = t->file.file_offset + t->file.left_length; if (end_offset > ((uint64_t)last_segment->segment_info.offset + last_segment->oper_offset)) { last_segment->oper_size = ngx_min((end_offset - (last_segment->segment_info.offset + last_segment->oper_offset)), last_segment->segment_info.size); } else { /* end_offset in file hole */ last_segment->oper_size = 0; } } /* check file hole */ if (t->r_ctx.chk_file_hole) { segment_data = t->file.segment_data; for (i = 0; i < count; i++, segment_data++) { /* must be file hole, add to array */ if (t->file.file_offset < segment_data->segment_info.offset) { curr_length = ngx_min(t->file.left_length, (uint64_t)(segment_data->segment_info.offset - t->file.file_offset)); file_hole_info = ngx_array_push(&t->file_holes); if (file_hole_info == NULL) { return NGX_ERROR; } file_hole_info->offset = t->file.file_offset; file_hole_info->length = curr_length; ngx_log_error(NGX_LOG_DEBUG, t->log, 0, "find file hole, offset: %uL, length: %uL", file_hole_info->offset, file_hole_info->length); t->file.file_offset += curr_length; t->file.left_length -= curr_length; if (t->file.left_length == 0) { return NGX_DECLINED; } } t->file.file_offset += segment_data->oper_size; t->file.left_length -= segment_data->oper_size; if (t->file.left_length == 0) { return NGX_DECLINED; } } return NGX_OK; } } #if (NGX_DEBUG) for (i = 0; i < count; i++) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, t->log, 0, "segment index: %d, oper_offset: %uD, oper_size: %uD", i, t->file.segment_data[i].oper_offset, t->file.segment_data[i].oper_size); } #endif ngx_log_error(NGX_LOG_DEBUG, t->log, 0, "still_have is %d, frag count is %d", t->file.still_have, count); return NGX_OK; }
static ngx_int_t ngx_rtmp_play_timestamp_to_offset(ngx_rtmp_session_t *s, ngx_int_t timestamp) { ngx_rtmp_play_ctx_t *ctx; ssize_t n, size; ngx_uint_t offset, index, ret, nelts; double v; ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); if (ctx == NULL) { goto rewind; } ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "play: lookup index start timestamp=%i", timestamp); if (ctx->meta_read == 0) { ngx_rtmp_play_read_meta(s); ctx->meta_read = 1; } if (timestamp <= 0 || ctx->filepositions.nelts == 0 || ctx->times.nelts == 0) { goto rewind; } /* read index table from file given offset */ offset = NGX_RTMP_PLAY_DATA_OFFSET + NGX_RTMP_PLAY_TAG_HEADER + ctx->times.offset; /* index should fit in the buffer */ nelts = ngx_min(ctx->times.nelts, sizeof(ngx_rtmp_play_buffer) / 9); size = nelts * 9; n = ngx_read_file(&ctx->file, ngx_rtmp_play_buffer, size, offset); if (n != size) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "play: could not read times index"); goto rewind; } /*TODO: implement binary search */ ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "play: lookup times nelts=%ui", nelts); for (index = 0; index < nelts - 1; ++index) { v = ngx_rtmp_play_index_value(ngx_rtmp_play_buffer + index * 9 + 1) * 1000; ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "play: lookup times index=%ui value=%ui", index, (ngx_uint_t) v); if (timestamp < v) { break; } } if (index >= ctx->filepositions.nelts) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "play: index out of bounds: %ui>=%ui", index, ctx->filepositions.nelts); goto rewind; } /* take value from filepositions */ offset = NGX_RTMP_PLAY_DATA_OFFSET + NGX_RTMP_PLAY_TAG_HEADER + ctx->filepositions.offset + index * 9; n = ngx_read_file(&ctx->file, ngx_rtmp_play_buffer, 8, offset + 1); if (n != 8) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "play: could not read filepositions index"); goto rewind; } ret = ngx_rtmp_play_index_value(ngx_rtmp_play_buffer); ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "play: lookup index timestamp=%i offset=%ui", timestamp, ret); return ret; rewind: ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "play: lookup index timestamp=%i offset=begin", timestamp); return NGX_RTMP_PLAY_DATA_OFFSET; }