void tfw_destroy_server(struct sock *s) { TfwConnection *conn = s->sk_user_data; TfwServer *srv; BUG_ON(!conn); srv = conn->hndl; /* The call back can be called twise bou our and Linux code. */ if (unlikely(!srv)) return; TFW_DBG("Destroy server socket %p\n", s); if (tfw_sched_del_srv(srv)) TFW_WARN("Try to delete orphaned server from" " requests scheduler"); srv->sock = NULL; conn->hndl = NULL; /* FIXME clear the server references from all current sessions. */ #if 0 kmem_cache_free(srv_cache, srv); #endif conn->sk_destruct(s); }
/** * Grow @str for @n new chunks. * New branches of the string tree are created on 2nd level only, * i.e. there is no possibility to grow number of chunks of duplicate string. * Pass pointer to one of the duplicates to do so. * @return pointer to the first of newly added chunk. * * TODO do we need exponential growing? */ static TfwStr * __str_grow_tree(TfwPool *pool, TfwStr *str, unsigned int flag, int n) { if (str->flags & flag) { unsigned int l; void *p; if (unlikely(TFW_STR_CHUNKN_LIM(str))) { TFW_WARN("Reaching chunks hard limit\n"); return NULL; } l = TFW_STR_CHUNKN(str) * sizeof(TfwStr); p = tfw_pool_realloc(pool, str->ptr, l, l + n * sizeof(TfwStr)); if (!p) return NULL; str->ptr = p; TFW_STR_CHUNKN_ADD(str, n); } else { TfwStr *a = tfw_pool_alloc(pool, (n + 1) * sizeof(TfwStr)); if (!a) return NULL; a[0] = *str; str->ptr = a; __TFW_STR_CHUNKN_SET(str, n + 1); } str = (TfwStr *)str->ptr + TFW_STR_CHUNKN(str) - n; memset(str, 0, sizeof(TfwStr) * n); return str; }
/** * Create a file in the debugfs, also create parent directories if needed and * remove the old file if it exists. * * @param path Path to a file to be created. * The path is always treated relative to the Tempesta root * directory in the debugfs (see tfw_debugfs_root). * @param data A pointer to some data which is saved in 'file' and 'inode' * structures. It may be retrieved by any function in @fops as * file->private_data or file->f_inode->i_private (it is copied * into both places). * @param fops A set of functions that handle system calls on the created file. * * * The function creates a file in the debugfs, but does it in a robust way: * - the file is replaced if it already exists * - all parent directories are created if they don't exist * * Returns: An ERR_PTR if the file is not created. */ static struct dentry * create_with_parents(const char *path, void *data, const struct file_operations *fops) { size_t name_size; char *buf, *pos, *component; struct dentry *parent, *child; /* Copy the path to a temporary buffer where it can be modified. */ name_size = strlen(path) + 1; buf = kmalloc(name_size, GFP_KERNEL); BUG_ON(ZERO_OR_NULL_PTR(buf)); strlcpy(buf, path, name_size); /* Eat the leading slash to allow specify either /foo/bar or foo/bar */ pos = buf; if (*pos == '/') ++pos; /* Walk over the path and create non-existing directories. */ parent = tfw_debugfs_root; component = pos; do { if (*pos != '/') continue; *pos = '\0'; child = lookup_file(component, parent); if (!child) { child = debugfs_create_dir(component, parent); BUG_ON(!parent); } parent = child; component = pos + 1; } while (*(++pos)); /* Remove the file if it already exists. */ child = lookup_file(component, parent); if (child) { TFW_DBG("Removing already existing debugfs file: %s\n", path); debugfs_remove(child); } /* Create the actual file. */ child = debugfs_create_file(component, S_IRWXU, parent, data, fops); if (IS_ERR_OR_NULL(child)) { int err = PTR_ERR(child); TFW_WARN("Can't create debugfs file: %s (%d)\n", path, err); } else { TFW_DBG("Created debugfs file: %s\n", path); } kfree(buf); return child; }
/** * Initialize the debugfs wrapper by creating a directory in the debugfs * where all files owned by the Tempesta FW are hosted. */ int tfw_debugfs_init(void) { int ret = 0; tfw_debugfs_root = debugfs_create_dir(TFW_DEBUGFS_ROOT_NAME, NULL); if (IS_ERR_OR_NULL(tfw_debugfs_root)) { ret = (int)PTR_ERR(tfw_debugfs_root); TFW_WARN("Can't create debugfs directory (%d)\n", ret); } return ret; }
static void tfw_bmb_msg_send(int tn, int cn) { TfwBmbTask *task = &bmb_task[tn]; int fz_tries = 0, r; TfwStr msg; TfwHttpMsg req; TfwMsgIter it; BUG_ON(!task->conn[cn].sk); do { if (++fz_tries > 10) { TFW_ERR("Too many fuzzer tries to generate request\n"); return; } r = fuzz_gen(&task->ctx, task->buf, task->buf + BUF_SIZE, 0, 1, FUZZ_REQ); if (r < 0) { TFW_ERR("Cannot generate HTTP request, r=%d\n", r); return; } if (r == FUZZ_END) fuzz_init(&task->ctx, true); } while (r != FUZZ_VALID); msg.ptr = task->buf; msg.skb = NULL; msg.len = strlen(msg.ptr); msg.flags = 0; if (!tfw_http_msg_create(&req, &it, Conn_Clnt, msg.len)) { TFW_WARN("Cannot create HTTP request.\n"); return; } if (verbose) TFW_LOG("Send request:\n" "------------------------------\n" "%s\n" "------------------------------\n", task->buf); tfw_http_msg_write(&it, &req, &msg); ss_send(task->conn[cn].sk, &req.msg.skb_list, true); atomic_inc(&bmb_request_send); }
/* * Find a connection for an outgoing HTTP request. * * The search is based on contents of an HTTP request and match rules * that specify which Server Group the request should be forwarded to. */ static TfwConnection * tfw_sched_http_sched_grp(TfwMsg *msg) { TfwSrvGroup *sg; TfwConnection *conn; TfwSchedHttpRule *rule; if(!tfw_sched_http_rules || list_empty(&tfw_sched_http_rules->list)) return NULL; rule = tfw_http_match_req_entry((TfwHttpReq *)msg, tfw_sched_http_rules, TfwSchedHttpRule, rule); if (unlikely(!rule)) { TFW_DBG("sched_http: No matching rule found.\n"); return NULL; } sg = rule->main_sg; BUG_ON(!sg); TFW_DBG("sched_http: use server group: '%s'\n", sg->name); conn = sg->sched->sched_srv(msg, sg); if (unlikely(!conn && rule->backup_sg)) { sg = rule->backup_sg; TFW_DBG("sched_http: the main group is offline, use backup:" " '%s'\n", sg->name); conn = sg->sched->sched_srv(msg, sg); } if (unlikely(!conn)) TFW_WARN("sched_http: Unable to select server from group" " '%s'\n", sg->name); return conn; }
/** * Work to copy response skbs to database mapped area. * * It's nasty to copy data on CPU, but we can't use DMA for mmaped file * as well as for unaligned memory areas. */ static void tfw_cache_copy_resp(struct work_struct *work) { int i; size_t hlens, tot_len; long n; char *p; TfwCWork *cw = (TfwCWork *)work; TfwCacheEntry *ce = cw->cw_ce; TdbVRec *trec; TfwHttpHdrTbl *htbl; TfwHttpHdr *hdr; BUG_ON(!ce->resp); /* Write HTTP headers. */ htbl = ce->resp->h_tbl; ce->hdr_num = htbl->size; hlens = sizeof(ce->hdr_lens[0]) * ce->hdr_num; tot_len = hlens + ce->resp->msg.len; /* * Try to place the cached response in single memory chunk. * * Number of HTTP headers is limited by TFW_HTTP_HDR_NUM_MAX while TDB * should be able to allocate an empty page if we issued a large * request. So HTTP header lengths must fit the first allocated data * chunk, also there must be some space for headers and message bodies. */ trec = tdb_entry_add(db, (TdbVRec *)ce, tot_len); if (!trec || trec->len <= hlens) { TFW_WARN("Cannot allocate memory to cache HTTP headers." " Probably TDB cache is exhausted.\n"); goto err; } p = (char *)(trec + 1) + hlens; tot_len -= hlens; /* * Set start of headers pointer just after array of * header length. */ ce->hdrs = p; hdr = htbl->tbl; for (i = 0; i < hlens / sizeof(ce->hdr_lens[0]); ++i, ++hdr) { n = tfw_cache_copy_str_compound(&p, &trec, &hdr->field, tot_len); if (n < 0) { TFW_ERR("Cache: cannot copy HTTP header\n"); goto err; } BUG_ON(n > tot_len); tot_len -= n; } /* Write HTTP response body. */ ce->body = p; n = tfw_cache_copy_str_compound(&p, &trec, &ce->resp->body, tot_len); if (n < 0) { TFW_ERR("Cache: cannot copy HTTP body\n"); goto err; } ce->body_len = n; err: /* FIXME all allocated TDB blocks are leaked here. */ kmem_cache_free(c_cache, cw); }