/** * 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; }
/** * 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(statsite_conn_handler *handle) { // Look for the next command line char *buf, *key, *val_str, *type_str, *endptr; metric_type type; int buf_len, should_free, status, i, after_len; double val; while (1) { status = extract_to_terminator(handle->conn, '\n', &buf, &buf_len, &should_free); if (status == -1) return 0; // Return if no command is available // Check for a valid metric // Scan for the colon status = buffer_after_terminator(buf, buf_len, ':', &val_str, &after_len); if (!status) status |= buffer_after_terminator(val_str, after_len, '|', &type_str, &after_len); if (status == 0) { // Convert the type switch (*type_str) { case 'c': type = COUNTER; break; case 'm': type = TIMER; break; case 'k': type = KEY_VAL; break; default: type = UNKNOWN; } // Convert the value to a double endptr = NULL; val = strtod(val_str, &endptr); // Store the sample if we did the conversion if (val != 0 || endptr != val_str) { metrics_add_sample(GLOBAL_METRICS, type, buf, val); } else { syslog(LOG_WARNING, "Failed value conversion! Input: %s", val_str); } } else { syslog(LOG_WARNING, "Failed parse metric! Input: %s", buf); } // Make sure to free the command buffer if we need to if (should_free) free(buf); } return 0; }
/** * Invoked to handle ASCII commands. This is the default * mode for statsite, to be backwards compatible with statsd * @arg handle The connection related information * @return 0 on success. */ static int handle_ascii_client_connect(statsite_conn_handler *handle) { // Look for the next command line char *buf, *key, *val_str, *type_str, *sample_str, *endptr; metric_type type; int buf_len, should_free, status, i, after_len; double val, sample_rate; while (1) { status = extract_to_terminator(handle->conn, '\n', &buf, &buf_len, &should_free); if (status == -1) return 0; // Return if no command is available // Check for a valid metric // Scan for the colon status = buffer_after_terminator(buf, buf_len, ':', &val_str, &after_len); if (likely(!status)) status |= buffer_after_terminator(val_str, after_len, '|', &type_str, &after_len); if (unlikely(status)) { syslog(LOG_WARNING, "Failed parse metric! Input: %s", buf); goto ERR_RET; } // Convert the type switch (*type_str) { case 'c': type = COUNTER; break; case 'm': type = TIMER; break; case 'k': type = KEY_VAL; break; case 'g': type = GAUGE; // Check if this is a delta update switch (*val_str) { case '+': // Advance past the + to avoid breaking str2double val_str++; case '-': type = GAUGE_DELTA; } break; case 's': type = SET; break; default: type = UNKNOWN; syslog(LOG_WARNING, "Received unknown metric type! Input: %c", *type_str); goto ERR_RET; } // Increment the number of inputs received if (GLOBAL_CONFIG->input_counter) metrics_add_sample(GLOBAL_METRICS, COUNTER, GLOBAL_CONFIG->input_counter, 1); // Fast track the set-updates if (type == SET) { metrics_set_update(GLOBAL_METRICS, buf, val_str); goto END_LOOP; } // Convert the value to a double val = str2double(val_str, &endptr); if (unlikely(endptr == val_str)) { syslog(LOG_WARNING, "Failed value conversion! Input: %s", val_str); goto ERR_RET; } // Handle counter sampling if applicable if (type == COUNTER && !buffer_after_terminator(type_str, after_len, '@', &sample_str, &after_len)) { sample_rate = str2double(sample_str, &endptr); if (unlikely(endptr == sample_str)) { syslog(LOG_WARNING, "Failed sample rate conversion! Input: %s", sample_str); goto ERR_RET; } if (sample_rate > 0 && sample_rate <= 1) { // Magnify the value val = val * (1.0 / sample_rate); } } // Store the sample metrics_add_sample(GLOBAL_METRICS, type, buf, val); END_LOOP: // Make sure to free the command buffer if we need to if (should_free) free(buf); } return 0; ERR_RET: if (should_free) free(buf); return -1; }
/** * Invoked to handle ASCII commands. This is the default * mode for statsite-proxy, to be backwards compatible with statsd * @arg handle The connection related information * @return 0 on success. */ static int handle_ascii_client_connect(statsite_proxy_conn_handler *handle) { // Look for the next command line char *buf, *val_str, *type_str; metric_type type; int buf_len, should_free, status, after_len, res; while (1) { status = extract_to_terminator(handle->conn, '\n', &buf, &buf_len, &should_free); if (status == -1) return 0; // Return if no command is available // Stack allocate space for message buffer char* proxy_msg = alloca((buf_len)* sizeof(char)); strncpy(proxy_msg, buf, buf_len); // Make sure to terminate strings *(proxy_msg + buf_len-1) = '\n'; // Check for a valid metric // Scan for the colon status = buffer_after_terminator(buf, buf_len, ':', &val_str, &after_len); if (!status) status |= buffer_after_terminator(val_str, after_len, '|', &type_str, &after_len); if (status == 0) { // Convert the type switch (*type_str) { case 'c': type = COUNTER; break; case 'm': type = TIMER; break; case 'k': case 'g': type = KEY_VAL; break; default: type = UNKNOWN; } // Route metric via consistent hash based on metric key void* conn; res = proxy_get_route_conn(handle->proxy, buf, &conn); if (res != 0) { syslog(LOG_WARNING, "Failed to find metric route! Metric key: %s", buf); } // Forward metric res = send_proxy_msg(conn, proxy_msg, buf_len); if (res != 0) { syslog(LOG_WARNING, "Failed to route metric route! Metric key: %s", buf); } } else { syslog(LOG_WARNING, "Failed parse metric! Input: %s", buf); } // Make sure to free the command buffer if we need to if (should_free) free(buf); } return 0; }