int rpc_decode(nw_ses *ses, void *data, size_t max) { if (max < RPC_PKG_HEAD_SIZE) return 0; rpc_pkg *pkg = data; if (le32toh(pkg->magic) != RPC_PKG_MAGIC) return -1; uint32_t pkg_size = RPC_PKG_HEAD_SIZE + le16toh(pkg->ext_size) + le32toh(pkg->body_size); if (max < pkg_size) return 0; uint32_t crc32 = le32toh(pkg->crc32); pkg->crc32 = 0; if (crc32 != generate_crc32c(data, pkg_size)) return -3; pkg->crc32 = crc32; pkg->magic = le32toh(pkg->magic); pkg->command = le32toh(pkg->command); pkg->pkg_type = le16toh(pkg->pkg_type); pkg->result = le32toh(pkg->result); pkg->sequence = le32toh(pkg->sequence); pkg->req_id = le64toh(pkg->req_id); pkg->body_size = le32toh(pkg->body_size); pkg->ext_size = le16toh(pkg->ext_size); return pkg_size; }
int rpc_pack(rpc_pkg *pkg, void **data, uint32_t *size) { static void *send_buf; static size_t send_buf_size; uint32_t pkg_size; if (pkg->body_size > RPC_PKG_MAX_BODY_SIZE) { return -1; } pkg_size = RPC_PKG_HEAD_SIZE + pkg->ext_size + pkg->body_size; if (send_buf_size < pkg_size) { if (send_buf) free(send_buf); send_buf_size = pkg_size * 2; send_buf = malloc(send_buf_size); if (send_buf == NULL) { return -1; } } memcpy(send_buf, pkg, RPC_PKG_HEAD_SIZE); if (pkg->ext_size) memcpy(send_buf + RPC_PKG_HEAD_SIZE, pkg->ext, pkg->ext_size); if (pkg->body_size) memcpy(send_buf + RPC_PKG_HEAD_SIZE + pkg->ext_size, pkg->body, pkg->body_size); pkg = send_buf; pkg->magic = htole32(RPC_PKG_MAGIC); pkg->command = htole32(pkg->command); pkg->pkg_type = htole16(pkg->pkg_type); pkg->result = htole32(pkg->result); pkg->sequence = htole32(pkg->sequence); pkg->req_id = htole64(pkg->req_id); pkg->body_size = htole32(pkg->body_size); pkg->ext_size = htole16(pkg->ext_size); pkg->crc32 = 0; pkg->crc32 = htole32(generate_crc32c(send_buf, pkg_size)); *data = send_buf; *size = pkg_size; return 0; }
static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; size_t s_len; unsigned long last_max = ULONG_MAX; int max_usage = INT_MAX; int ndx = -1; size_t k; buffer *fn; data_array *extension = NULL; size_t path_info_offset; if (con->mode != DIRECT) return HANDLER_GO_ON; /* Possibly, we processed already this request */ if (con->file_started == 1) return HANDLER_GO_ON; mod_proxy_patch_connection(srv, con, p); fn = con->uri.path; if (fn->used == 0) { return HANDLER_ERROR; } s_len = fn->used - 1; path_info_offset = 0; if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start"); } /* check if extension matches */ for (k = 0; k < p->conf.extensions->used; k++) { data_array *ext = NULL; size_t ct_len; ext = (data_array *)p->conf.extensions->data[k]; if (ext->key->used == 0) continue; ct_len = ext->key->used - 1; if (s_len < ct_len) continue; /* check extension in the form "/proxy_pattern" */ if (*(ext->key->ptr) == '/') { if (strncmp(fn->ptr, ext->key->ptr, ct_len) == 0) { if (s_len > ct_len + 1) { char *pi_offset; if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) { path_info_offset = pi_offset - fn->ptr; } } extension = ext; break; } } else if (0 == strncmp(fn->ptr + s_len - ct_len, ext->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ extension = ext; break; } } if (NULL == extension) { return HANDLER_GO_ON; } if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found"); } if (extension->value->used == 1) { if ( ((data_proxy *)extension->value->data[0])->is_disabled ) { ndx = -1; } else { ndx = 0; } } else if (extension->value->used != 0) switch(p->conf.balance) { case PROXY_BALANCE_HASH: /* hash balancing */ if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sd", "proxy - used hash balancing, hosts:", extension->value->used); } for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) { data_proxy *host = (data_proxy *)extension->value->data[k]; unsigned long cur_max; if (host->is_disabled) continue; cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) + generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */ generate_crc32c(CONST_BUF_LEN(con->uri.authority)); if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sbbbd", "proxy - election:", con->uri.path, host->host, con->uri.authority, cur_max); } if ((last_max == ULONG_MAX) || /* first round */ (cur_max > last_max)) { last_max = cur_max; ndx = k; } } break; case PROXY_BALANCE_FAIR: /* fair balancing */ if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - used fair balancing"); } for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) { data_proxy *host = (data_proxy *)extension->value->data[k]; if (host->is_disabled) continue; if (host->usage < max_usage) { max_usage = host->usage; ndx = k; } } break; case PROXY_BALANCE_RR: { data_proxy *host; /* round robin */ if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - used round-robin balancing"); } /* just to be sure */ assert(extension->value->used < INT_MAX); host = (data_proxy *)extension->value->data[0]; /* Use last_used_ndx from first host in list */ k = host->last_used_ndx; ndx = k + 1; /* use next host after the last one */ if (ndx < 0) ndx = 0; /* Search first active host after last_used_ndx */ while ( ndx < (int) extension->value->used && (host = (data_proxy *)extension->value->data[ndx])->is_disabled ) ndx++; if (ndx >= (int) extension->value->used) { /* didn't found a higher id, wrap to the start */ for (ndx = 0; ndx <= (int) k; ndx++) { host = (data_proxy *)extension->value->data[ndx]; if (!host->is_disabled) break; } /* No active host found */ if (host->is_disabled) ndx = -1; } /* Save new index for next round */ ((data_proxy *)extension->value->data[0])->last_used_ndx = ndx; break; } default: break; } /* found a server */ if (ndx != -1) { data_proxy *host = (data_proxy *)extension->value->data[ndx]; /* * if check-local is disabled, use the uri.path handler * */ /* init handler-context */ handler_ctx *hctx; hctx = handler_ctx_init(); hctx->path_info_offset = path_info_offset; hctx->remote_conn = con; hctx->plugin_data = p; hctx->host = host; con->plugin_ctx[p->id] = hctx; host->usage++; con->mode = p->id; if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sbd", "proxy - found a host", host->host, host->port); } return HANDLER_GO_ON; } else { /* no handler found */ con->http_status = 500; log_error_write(srv, __FILE__, __LINE__, "sb", "no proxy-handler found for:", fn); return HANDLER_FINISHED; } return HANDLER_GO_ON; }