/** * Internal method to handle a command that relies * on a filter name and a single key, responses are handled using * handle_multi_response. */ static void handle_filt_cmd(bloom_conn_handler *handle, char *args, int args_len, int(*filtmgr_func)(bloom_filtmgr *, char*)) { // If we have no args, complain. if (!args) { handle_client_err(handle->conn, (char*)&FILT_NEEDED, FILT_NEEDED_LEN); return; } // Scan past the filter name char *key; int key_len; int after = buffer_after_terminator(args, args_len, ' ', &key, &key_len); if (after == 0) { handle_client_err(handle->conn, (char*)&UNEXPECTED_ARGS, UNEXPECTED_ARGS_LEN); return; } // Call into the filter manager int res = filtmgr_func(handle->mgr, args); switch (res) { case 0: handle_client_resp(handle->conn, (char*)DONE_RESP, DONE_RESP_LEN); break; case -1: handle_client_resp(handle->conn, (char*)FILT_NOT_EXIST, FILT_NOT_EXIST_LEN); break; case -2: handle_client_resp(handle->conn, (char*)FILT_NOT_PROXIED, FILT_NOT_PROXIED_LEN); break; default: INTERNAL_ERROR(); break; } }
/** * Invoked by the networking layer when there is new * data to be handled. The connection handler should * consume all the input possible, and generate responses * to all requests. * @arg handle The connection related information * @return 0 on success. */ int handle_client_connect(bloom_conn_handler *handle) { // Look for the next command line char *buf, *arg_buf; int buf_len, arg_buf_len, should_free; int status; while (1) { status = extract_to_terminator(handle->conn, '\n', &buf, &buf_len, &should_free); if (status == -1) break; // Return if no command is available // Determine the command type conn_cmd_type type = determine_client_command(buf, buf_len, &arg_buf, &arg_buf_len); // Handle an error or unknown response switch(type) { case CHECK: handle_check_cmd(handle, arg_buf, arg_buf_len); break; case CHECK_MULTI: handle_check_multi_cmd(handle, arg_buf, arg_buf_len); break; case SET: handle_set_cmd(handle, arg_buf, arg_buf_len); break; case SET_MULTI: handle_set_multi_cmd(handle, arg_buf, arg_buf_len); break; case CREATE: handle_create_cmd(handle, arg_buf, arg_buf_len); break; case DROP: handle_drop_cmd(handle, arg_buf, arg_buf_len); break; case CLOSE: handle_close_cmd(handle, arg_buf, arg_buf_len); break; case CLEAR: handle_clear_cmd(handle, arg_buf, arg_buf_len); break; case LIST: handle_list_cmd(handle, arg_buf, arg_buf_len); break; case INFO: handle_info_cmd(handle, arg_buf, arg_buf_len); break; case FLUSH: handle_flush_cmd(handle, arg_buf, arg_buf_len); break; default: handle_client_err(handle->conn, (char*)&CMD_NOT_SUP, CMD_NOT_SUP_LEN); break; } // Make sure to free the command buffer if we need to if (should_free) free(buf); } return 0; }
static void handle_info_cmd(bloom_conn_handler *handle, char *args, int args_len) { // If we have no args, complain. if (!args) { handle_client_err(handle->conn, (char*)&FILT_NEEDED, FILT_NEEDED_LEN); return; } // Scan past the filter name char *key; int key_len; int after = buffer_after_terminator(args, args_len, ' ', &key, &key_len); if (after == 0) { handle_client_err(handle->conn, (char*)&UNEXPECTED_ARGS, UNEXPECTED_ARGS_LEN); return; } // Create output buffers char *output[] = {(char*)&START_RESP, NULL, (char*)&END_RESP}; int lens[] = {START_RESP_LEN, 0, END_RESP_LEN}; // Invoke the callback to get the filter stats int res = filtmgr_filter_cb(handle->mgr, args, info_filter_cb, &output[1]); // Check for no filter if (res != 0) { switch (res) { case -1: handle_client_resp(handle->conn, (char*)FILT_NOT_EXIST, FILT_NOT_EXIST_LEN); break; default: INTERNAL_ERROR(); break; } return; } // Adjust the buffer size lens[1] = strlen(output[1]); // Write out the bufs send_client_response(handle->conn, (char**)&output, (int*)&lens, 3); free(output[1]); }
/** * Internal command used to handle filter creation. */ static void handle_create_cmd(bloom_conn_handler *handle, char *args, int args_len) { // If we have no args, complain. if (!args) { handle_client_err(handle->conn, (char*)&FILT_NEEDED, FILT_NEEDED_LEN); return; } // Scan for options after the filter name char *options; int options_len; int res = buffer_after_terminator(args, args_len, ' ', &options, &options_len); // Verify the filter name is valid char *filter_name = args; if (regexec(&VALID_FILTER_NAMES_RE, filter_name, 0, NULL, 0) != 0) { handle_client_err(handle->conn, (char*)&BAD_FILT_NAME, BAD_FILT_NAME_LEN); return; } // Parse the options bloom_config *config = NULL; int err = 0; if (res == 0) { // Make a new config store, copy the current config = malloc(sizeof(bloom_config)); memcpy(config, handle->config, sizeof(bloom_config)); // Parse any options char *param = options; while (param) { // Adds a zero terminator to the current param, scans forward buffer_after_terminator(options, options_len, ' ', &options, &options_len); // Check for the custom params int match = 0; match |= sscanf(param, "capacity=%llu", (unsigned long long*)&config->initial_capacity); match |= sscanf(param, "prob=%lf", &config->default_probability); match |= sscanf(param, "in_memory=%d", &config->in_memory); // Check if there was no match if (!match) { err = 1; handle_client_err(handle->conn, (char*)&BAD_ARGS, BAD_ARGS_LEN); break; } // Advance to the next param param = options; } // Validate the params int invalid_config = 0; invalid_config |= sane_initial_capacity(config->initial_capacity); invalid_config |= sane_default_probability(config->default_probability); invalid_config |= sane_in_memory(config->in_memory); // Barf if the configs are bad if (invalid_config) { err = 1; handle_client_err(handle->conn, (char*)&BAD_ARGS, BAD_ARGS_LEN); } } // Clean up an leave on errors if (err) { if (config) free(config); return; } // Create a new filter res = filtmgr_create_filter(handle->mgr, filter_name, config); switch (res) { case 0: handle_client_resp(handle->conn, (char*)DONE_RESP, DONE_RESP_LEN); break; case -1: handle_client_resp(handle->conn, (char*)EXISTS_RESP, EXISTS_RESP_LEN); if (config) free(config); break; case -3: handle_client_resp(handle->conn, (char*)DELETE_IN_PROGRESS, DELETE_IN_PROGRESS_LEN); if (config) free(config); break; default: INTERNAL_ERROR(); if (config) free(config); break; } }