| /** @file |
| |
| This file implements the LogAccess class. |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| |
| @section description |
| This file implements the LogAccess class. However, LogAccess is an |
| abstract base class, providing an interface that logging uses to get |
| information from a module, such as HTTP or ICP. Each module derives a |
| specific implementation from this base class (such as LogAccessHttp), and |
| implements the virtual accessor functions there. |
| |
| The LogAccess class also defines a set of static functions that are used |
| to provide support for marshalling and unmarshalling support for the other |
| LogAccess derived classes. |
| */ |
| #include "libts.h" |
| |
| #include "Error.h" |
| #include "HTTP.h" |
| |
| #include "P_Net.h" |
| #include "P_Cache.h" |
| #include "I_Machine.h" |
| #include "LogAccess.h" |
| #include "LogField.h" |
| #include "LogFilter.h" |
| #include "LogUtils.h" |
| #include "LogFormat.h" |
| #include "LogObject.h" |
| #include "LogConfig.h" |
| #include "LogBuffer.h" |
| #include "Log.h" |
| |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::init |
| -------------------------------------------------------------------------*/ |
| |
| void |
| LogAccess::init() |
| { |
| if (initialized) { |
| return; |
| } |
| // |
| // Here is where we would perform any initialization code. |
| // |
| |
| initialized = true; |
| } |
| |
| /*------------------------------------------------------------------------- |
| The following functions provide a default implementation for the base |
| class marshalling routines so that each subsequent LogAccess* class only |
| has to implement those functions that are to override this default |
| implementation. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_plugin_identity_id(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| int |
| LogAccess::marshal_plugin_identity_tag(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| int |
| LogAccess::marshal_client_host_ip(char *buf) |
| { |
| DEFAULT_IP_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_host_port(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_auth_user_name(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_text(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_http_method(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_url(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_url_canon(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_unmapped_url_canon(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_unmapped_url_path(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_unmapped_url_host(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_url_path(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_url_scheme(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| This case is special because it really stores 2 ints. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_http_version(char *buf) |
| { |
| if (buf) { |
| int64_t major = 0; |
| int64_t minor = 0; |
| marshal_int(buf, major); |
| marshal_int((buf + INK_MIN_ALIGN), minor); |
| } |
| return (2 * INK_MIN_ALIGN); |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_header_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_body_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_finish_status_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_resp_content_type(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_resp_squid_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_resp_content_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_resp_status_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_resp_header_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_finish_status_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_cache_result_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_req_header_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_req_body_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_req_server_name(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_req_server_ip(char *buf) |
| { |
| DEFAULT_IP_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_hierarchy_route(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| #ifndef INK_NO_CONGESTION_CONTROL |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_retry_after_time(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| #endif |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_host_name(char *buf) |
| { |
| char *str = NULL; |
| int len = 0; |
| Machine *machine = Machine::instance(); |
| |
| if (machine) { |
| str = machine->hostname; |
| } |
| |
| len = LogAccess::strlen(str); |
| |
| if (buf) { |
| marshal_str(buf, str, len); |
| } |
| |
| return len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_proxy_host_ip(char *buf) |
| { |
| return marshal_ip(buf, &Machine::instance()->ip.sa); |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_server_host_ip(char *buf) |
| { |
| DEFAULT_IP_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_server_host_name(char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_server_resp_status_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_server_resp_content_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_server_resp_header_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| This case is special because it really stores 2 ints. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_server_resp_http_version(char *buf) |
| { |
| if (buf) { |
| int64_t major = 0; |
| int64_t minor = 0; |
| marshal_int(buf, major); |
| marshal_int((buf + INK_MIN_ALIGN), minor); |
| } |
| return (2 * INK_MIN_ALIGN); |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_cache_resp_status_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_cache_resp_content_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_cache_resp_header_len(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| This case is special because it really stores 2 ints. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_cache_resp_http_version(char *buf) |
| { |
| if (buf) { |
| int64_t major = 0; |
| int64_t minor = 0; |
| marshal_int(buf, major); |
| marshal_int((buf + INK_MIN_ALIGN), minor); |
| } |
| return (2 * INK_MIN_ALIGN); |
| } |
| |
| int |
| LogAccess::marshal_cache_write_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| int |
| LogAccess::marshal_cache_write_transform_code(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_transfer_time_ms(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| int |
| LogAccess::marshal_transfer_time_s(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_file_size(char *buf) |
| { |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| int |
| LogAccess::marshal_http_header_field(LogField::Container /* container ATS_UNUSED */, |
| char * /* field ATS_UNUSED */, char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| |
| -------------------------------------------------------------------------*/ |
| int |
| LogAccess::marshal_http_header_field_escapify(LogField::Container /* container ATS_UNUSED */, |
| char * /* field ATS_UNUSED */, char *buf) |
| { |
| DEFAULT_STR_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| |
| The following functions have a non-virtual base-class implementation. |
| -------------------------------------------------------------------------*/ |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::marshal_client_req_timestamp_sec |
| |
| This does nothing because the timestamp is already in the LogEntryHeader. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_client_req_timestamp_sec(char *buf) |
| { |
| // in the case of aggregate fields, we need the space, so we'll always |
| // reserve it. For a non-aggregate timestamp, this space is not used. |
| DEFAULT_INT_FIELD; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_entry_type(char *buf) |
| { |
| if (buf) { |
| int64_t val = (int64_t) entry_type(); |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_config_int_var(char *config_var, char *buf) |
| { |
| if (buf) { |
| int64_t val = (int64_t) REC_ConfigReadInteger(config_var); |
| marshal_int(buf, val); |
| } |
| return INK_MIN_ALIGN; |
| } |
| |
| /*------------------------------------------------------------------------- |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_config_str_var(char *config_var, char *buf) |
| { |
| char *str = NULL; |
| str = REC_ConfigReadString(config_var); |
| int len = LogAccess::strlen(str); |
| if (buf) { |
| marshal_str(buf, str, len); |
| } |
| ats_free(str); |
| return len; |
| } |
| |
| // To allow for a generic marshal_record function, rather than |
| // multiple functions (one per data type) we always marshal a record |
| // as a string of a fixed length. We use a fixed length because the |
| // marshal_record function can be called with a null *buf to request |
| // the length of the record, and later with a non-null *buf to |
| // actually request the record to be inserted in the buffer, and both |
| // calls should return the same number of characters. If we did not |
| // enforce a fixed size, this would not necesarilly be the case |
| // because records --statistics in particular-- can potentially change |
| // between one call and the other. |
| // |
| int |
| LogAccess::marshal_record(char *record, char *buf) |
| { |
| const unsigned int max_chars = MARSHAL_RECORD_LENGTH; |
| |
| if (NULL == buf) { |
| return max_chars; |
| } |
| |
| const char *record_not_found_msg = "RECORD_NOT_FOUND"; |
| const unsigned int record_not_found_chars = ::strlen(record_not_found_msg) + 1; |
| |
| char ascii_buf[max_chars]; |
| const char *out_buf; |
| unsigned int num_chars; |
| |
| #define LOG_INTEGER RECD_INT |
| #define LOG_COUNTER RECD_COUNTER |
| #define LOG_FLOAT RECD_FLOAT |
| #define LOG_STRING RECD_STRING |
| |
| RecDataT stype = RECD_NULL; |
| bool found = false; |
| |
| if (RecGetRecordDataType(record, &stype) != REC_ERR_OKAY) { |
| out_buf = "INVALID_RECORD"; |
| num_chars = ::strlen(out_buf) + 1; |
| } else { |
| if (LOG_INTEGER == stype || LOG_COUNTER == stype) { |
| // we assume MgmtInt and MgmtIntCounter are int64_t for the |
| // conversion below, if this ever changes we should modify |
| // accordingly |
| // |
| ink_assert(sizeof(int64_t) >= sizeof(RecInt) && sizeof(int64_t) >= sizeof(RecCounter)); |
| |
| // so that a 64 bit integer will fit (including sign and eos) |
| // |
| ink_assert(max_chars > 21); |
| |
| int64_t val = (int64_t) (LOG_INTEGER == stype ? REC_readInteger(record, &found) : REC_readCounter(record, &found)); |
| |
| if (found) { |
| |
| out_buf = int64_to_str(ascii_buf, max_chars, val, &num_chars); |
| ink_assert(out_buf); |
| } else { |
| out_buf = (char *) record_not_found_msg; |
| num_chars = record_not_found_chars; |
| } |
| } else if (LOG_FLOAT == stype) { |
| // we assume MgmtFloat is at least a float for the conversion below |
| // (the conversion itself assumes a double because of the %e) |
| // if this ever changes we should modify accordingly |
| // |
| ink_assert(sizeof(double) >= sizeof(RecFloat)); |
| |
| RecFloat val = REC_readFloat(record, &found); |
| |
| if (found) { |
| // snprintf does not support "%e" in the format |
| // and we want to use "%e" because it is the most concise |
| // notation |
| |
| num_chars = snprintf(ascii_buf, sizeof(ascii_buf), "%e", val) + 1; // include eos |
| |
| // the "%e" field above should take 13 characters at most |
| // |
| ink_assert(num_chars <= max_chars); |
| |
| // the following should never be true |
| // |
| if (num_chars > max_chars) { |
| // data does not fit, output asterisks |
| out_buf = "***"; |
| num_chars = ::strlen(out_buf) + 1; |
| } else { |
| out_buf = ascii_buf; |
| } |
| } else { |
| out_buf = (char *) record_not_found_msg; |
| num_chars = record_not_found_chars; |
| } |
| } else if (LOG_STRING == stype) { |
| out_buf = REC_readString(record, &found); |
| |
| if (found) { |
| if (out_buf != 0 && out_buf[0] != 0) { |
| num_chars =::strlen(out_buf) + 1; |
| if (num_chars > max_chars) { |
| // truncate string and write ellipsis at the end |
| memcpy(ascii_buf, out_buf, max_chars - 4); |
| ascii_buf[max_chars - 1] = 0; |
| ascii_buf[max_chars - 2] = '.'; |
| ascii_buf[max_chars - 3] = '.'; |
| ascii_buf[max_chars - 4] = '.'; |
| out_buf = ascii_buf; |
| num_chars = max_chars; |
| } |
| } else { |
| out_buf = "NULL"; |
| num_chars = ::strlen(out_buf) + 1; |
| } |
| } else { |
| out_buf = (char *) record_not_found_msg; |
| num_chars = record_not_found_chars; |
| } |
| } else { |
| out_buf = "INVALID_MgmtType"; |
| num_chars = ::strlen(out_buf) + 1; |
| ink_assert(!"invalid MgmtType for requested record"); |
| } |
| } |
| |
| ink_assert(num_chars <= max_chars); |
| memcpy(buf, out_buf, num_chars); |
| |
| |
| return max_chars; |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::marshal_str |
| |
| Copy the given string to the destination buffer, including the trailing |
| NULL. For binary formatting, we need the NULL to distinguish the end of |
| the string, and we'll remove it for ascii formatting. |
| ASSUMES dest IS NOT NULL. |
| The array pointed to by dest must be at least padded_len in length. |
| -------------------------------------------------------------------------*/ |
| |
| void |
| LogAccess::marshal_str(char *dest, const char *source, int padded_len) |
| { |
| if (source == NULL || source[0] == 0 || padded_len == 0) { |
| source = DEFAULT_STR; |
| } |
| ink_strlcpy(dest, source, padded_len); |
| |
| #ifdef DEBUG |
| // |
| // what padded_len should be, if there is no padding, is strlen()+1. |
| // if not, then we needed to pad and should touch the intermediate |
| // bytes to avoid UMR errors when the buffer is written. |
| // |
| size_t real_len = (::strlen(source) + 1); |
| while ((int) real_len < padded_len) { |
| dest[real_len] = '$'; |
| real_len++; |
| } |
| #endif |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::marshal_mem |
| |
| This is a version of marshal_str that works with unterminated strings. |
| In this case, we'll copy the buffer and then add a trailing null that |
| the rest of the system assumes. |
| -------------------------------------------------------------------------*/ |
| |
| void |
| LogAccess::marshal_mem(char *dest, const char *source, int actual_len, int padded_len) |
| { |
| if (source == NULL || source[0] == 0 || actual_len == 0) { |
| source = DEFAULT_STR; |
| actual_len = DEFAULT_STR_LEN; |
| ink_assert(actual_len < padded_len); |
| } |
| memcpy(dest, source, actual_len); |
| dest[actual_len] = 0; // add terminating null |
| |
| #ifdef DEBUG |
| // |
| // what len should be, if there is no padding, is strlen()+1. |
| // if not, then we needed to pad and should touch the intermediate |
| // bytes to avoid UMR errors when the buffer is written. |
| // |
| int real_len = actual_len + 1; |
| while (real_len < padded_len) { |
| dest[real_len] = '$'; |
| real_len++; |
| } |
| #endif |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::marshal_ip |
| |
| Marshal an IP address in a reasonably compact way. If the address isn't |
| valid (NULL or not IP) then marshal an invalid address record. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::marshal_ip(char* dest, sockaddr const* ip) { |
| LogFieldIpStorage data; |
| int len = sizeof(data._ip); |
| if (NULL == ip) { |
| data._ip._family = AF_UNSPEC; |
| } else if (ats_is_ip4(ip)) { |
| if (dest) { |
| data._ip4._family = AF_INET; |
| data._ip4._addr = ats_ip4_addr_cast(ip); |
| } |
| len = sizeof(data._ip4); |
| } else if (ats_is_ip6(ip)) { |
| if (dest) { |
| data._ip6._family = AF_INET6; |
| data._ip6._addr = ats_ip6_addr_cast(ip); |
| } |
| len = sizeof(data._ip6); |
| } else { |
| data._ip._family = AF_UNSPEC; |
| } |
| |
| if (dest) memcpy(dest, &data, len); |
| return INK_ALIGN_DEFAULT(len); |
| } |
| |
| inline int |
| LogAccess::unmarshal_with_map(int64_t code, char *dest, int len, Ptr<LogFieldAliasMap> map, const char *msg) |
| { |
| int codeStrLen; |
| |
| switch (map->asString(code, dest, len, (size_t *) & codeStrLen)) { |
| case LogFieldAliasMap::INVALID_INT: |
| if (msg) { |
| const int bufSize = 64; |
| char invalidCodeMsg[bufSize]; |
| codeStrLen = snprintf(invalidCodeMsg, 64, "%s(%" PRId64 ")", msg, code); |
| if (codeStrLen < bufSize && codeStrLen < len) { |
| ink_strlcpy(dest, invalidCodeMsg, len); |
| } else { |
| codeStrLen = -1; |
| } |
| } else { |
| codeStrLen = -1; |
| } |
| break; |
| case LogFieldAliasMap::BUFFER_TOO_SMALL: |
| codeStrLen = -1; |
| break; |
| } |
| |
| return codeStrLen; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_int |
| |
| Return the integer pointed at by the buffer and advance the buffer |
| pointer past the int. The int will be converted back to host byte order. |
| -------------------------------------------------------------------------*/ |
| |
| int64_t |
| LogAccess::unmarshal_int(char **buf) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| int64_t val; |
| |
| // TODO: this used to do nthol, do we need to worrry? TS-1156. |
| val = *((int64_t *)(*buf)); |
| *buf += INK_MIN_ALIGN; |
| return val; |
| } |
| |
| /*------------------------------------------------------------------------- |
| unmarshal_itoa |
| |
| This routine provides a fast conversion from a binary int to a string. |
| It returns the number of characters formatted. "dest" must point to the |
| LAST character of an array large enough to store the complete formatted |
| number. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_itoa(int64_t val, char *dest, int field_width, char leading_char) |
| { |
| ink_assert(dest != NULL); |
| |
| char *p = dest; |
| |
| if (val <= 0) { |
| *p-- = '0'; |
| while (dest - p < field_width) { |
| *p-- = leading_char; |
| } |
| return (int)(dest - p); |
| } |
| |
| while (val) { |
| *p-- = '0' + (val % 10); |
| val /= 10; |
| } |
| while (dest - p < field_width) { |
| *p-- = leading_char; |
| } |
| return (int)(dest - p); |
| } |
| |
| /*------------------------------------------------------------------------- |
| unmarshal_itox |
| |
| This routine provides a fast conversion from a binary int to a hex string. |
| It returns the number of characters formatted. "dest" must point to the |
| LAST character of an array large enough to store the complete formatted |
| number. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_itox(int64_t val, char *dest, int field_width, char leading_char) |
| { |
| ink_assert(dest != NULL); |
| |
| char *p = dest; |
| static char table[] = "0123456789abcdef?"; |
| |
| for (int i = 0; i < (int)(sizeof(int64_t) * 2); i++) { |
| *p-- = table[val & 0xf]; |
| val >>= 4; |
| } |
| while (dest - p < field_width) { |
| *p-- = leading_char; |
| } |
| |
| return (int64_t)(dest - p); |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_int_to_str |
| |
| Return the string representation of the integer pointed at by buf. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_int_to_str(char **buf, char *dest, int len) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| char val_buf[128]; |
| int64_t val = unmarshal_int(buf); |
| int val_len = unmarshal_itoa(val, val_buf + 127); |
| |
| if (val_len < len) { |
| memcpy(dest, val_buf + 128 - val_len, val_len); |
| return val_len; |
| } |
| return -1; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_int_to_str_hex |
| |
| Return the string representation (hexadecimal) of the integer pointed at by buf. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_int_to_str_hex(char **buf, char *dest, int len) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| char val_buf[128]; |
| int64_t val = unmarshal_int(buf); |
| int val_len = unmarshal_itox(val, val_buf + 127); |
| |
| if (val_len < len) { |
| memcpy(dest, val_buf + 128 - val_len, val_len); |
| return val_len; |
| } |
| return -1; |
| } |
| |
| |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_str |
| |
| Retrieve the string from the location pointed at by the buffer and |
| advance the pointer past the string. The local strlen function is used |
| to advance the pointer, thus matching the corresponding strlen that was |
| used to lay the string into the buffer. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_str(char **buf, char *dest, int len, LogSlice *slice) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| char *val_buf = *buf; |
| int val_len = (int)::strlen(val_buf); |
| |
| *buf += LogAccess::strlen(val_buf); // this is how it was stored |
| |
| if (slice && slice->m_enable) { |
| int offset, n; |
| |
| n = slice->toStrOffset(val_len, &offset); |
| if (n <= 0) |
| return 0; |
| |
| if (n >= len) |
| return -1; |
| |
| memcpy(dest, (val_buf + offset), n); |
| return n; |
| } |
| |
| if (val_len < len) { |
| memcpy(dest, val_buf, val_len); |
| return val_len; |
| } |
| return -1; |
| } |
| |
| int |
| LogAccess::unmarshal_ttmsf(char **buf, char *dest, int len) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| int64_t val = unmarshal_int(buf); |
| float secs = (float) val / 1000; |
| int val_len = snprintf(dest, len, "%.3f", secs); |
| return val_len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_http_method |
| |
| Retrieve the int pointed at by the buffer and treat as an HttpMethod |
| enumerated type. Then lookup the string representation for that enum and |
| return the string. Advance the buffer pointer past the enum. |
| -------------------------------------------------------------------------*/ |
| /* |
| int |
| LogAccess::unmarshal_http_method (char **buf, char *dest, int len) |
| { |
| return unmarshal_str (buf, dest, len); |
| } |
| */ |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_http_version |
| |
| The http version is marshalled as two consecutive integers, the first for |
| the major number and the second for the minor number. Retrieve both |
| numbers and return the result as "HTTP/major.minor". |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_http_version(char **buf, char *dest, int len) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| static const char *http = "HTTP/"; |
| static int http_len = (int)::strlen(http); |
| |
| char val_buf[128]; |
| char *p = val_buf; |
| |
| memcpy(p, http, http_len); |
| p += http_len; |
| |
| int res1 = unmarshal_int_to_str(buf, p, 128 - http_len); |
| if (res1 < 0) { |
| return -1; |
| } |
| p += res1; |
| *p++ = '.'; |
| int res2 = unmarshal_int_to_str(buf, p, 128 - http_len - res1 - 1); |
| if (res2 < 0) { |
| return -1; |
| } |
| |
| int val_len = http_len + res1 + res2 + 1; |
| if (val_len < len) { |
| memcpy(dest, val_buf, val_len); |
| return val_len; |
| } |
| return -1; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_http_text |
| |
| The http text is simply the fields http_method (cqhm) + url (cqu) + |
| http_version (cqhv), all right next to each other, in that order. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_http_text(char **buf, char *dest, int len, LogSlice *slice) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| char *p = dest; |
| |
| // int res1 = unmarshal_http_method (buf, p, len); |
| int res1 = unmarshal_str(buf, p, len); |
| if (res1 < 0) { |
| return -1; |
| } |
| p += res1; |
| *p++ = ' '; |
| int res2 = unmarshal_str(buf, p, len - res1 - 1, slice); |
| if (res2 < 0) { |
| return -1; |
| } |
| p += res2; |
| *p++ = ' '; |
| int res3 = unmarshal_http_version(buf, p, len - res1 - res2 - 2); |
| if (res3 < 0) { |
| return -1; |
| } |
| return res1 + res2 + res3 + 2; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_http_status |
| |
| An http response status code (pssc,sssc) is just an INT, but it's always |
| formatted with three digits and leading zeros. So, we need a special |
| version of unmarshal_int_to_str that does this leading zero formatting. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_http_status(char **buf, char *dest, int len) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| char val_buf[128]; |
| int64_t val = unmarshal_int(buf); |
| int val_len = unmarshal_itoa(val, val_buf + 127, 3, '0'); |
| if (val_len < len) { |
| memcpy(dest, val_buf + 128 - val_len, val_len); |
| return val_len; |
| } |
| return -1; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_ip |
| |
| Retrieve an IP address directly. |
| -------------------------------------------------------------------------*/ |
| int |
| LogAccess::unmarshal_ip(char **buf, IpEndpoint* dest) |
| { |
| int len = sizeof(LogFieldIp); // of object processed. |
| |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| LogFieldIp* raw = reinterpret_cast<LogFieldIp*>(*buf); |
| if (AF_INET == raw->_family) { |
| LogFieldIp4* ip4 = static_cast<LogFieldIp4*>(raw); |
| ats_ip4_set(dest, ip4->_addr); |
| len = sizeof(*ip4); |
| } else if (AF_INET6 == raw->_family) { |
| LogFieldIp6* ip6 = static_cast<LogFieldIp6*>(raw); |
| ats_ip6_set(dest, ip6->_addr); |
| len = sizeof(*ip6); |
| } else { |
| ats_ip_invalidate(dest); |
| } |
| len = INK_ALIGN_DEFAULT(len); |
| *buf += len; |
| return len; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_ip_to_str |
| |
| Retrieve the IP addresspointed at by the buffer and convert to a |
| string in standard format. The string is written to @a dest and its |
| length (not including nul) is returned. @a *buf is advanced. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_ip_to_str(char **buf, char *dest, int len) |
| { |
| IpEndpoint ip; |
| int zret = -1; |
| |
| if (len > 0) { |
| unmarshal_ip(buf, &ip); |
| if (!ats_is_ip(&ip)) { |
| *dest = '0'; |
| zret = 1; |
| } else if (ats_ip_ntop(&ip, dest, len)) { |
| zret = static_cast<int>(::strlen(dest)); |
| } |
| } |
| return zret; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_ip_to_hex |
| |
| Retrieve the int pointed at by the buffer and treat as an IP |
| address. Convert to a string in byte oriented hexadeciaml and |
| return the string. Advance the buffer pointer. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_ip_to_hex(char **buf, char *dest, int len) |
| { |
| int zret = -1; |
| IpEndpoint ip; |
| |
| if (len > 0) { |
| unmarshal_ip(buf, &ip); |
| if (!ats_is_ip(&ip)) { |
| *dest = '0'; |
| zret = 1; |
| } else { |
| zret = ats_ip_to_hex(&ip.sa, dest, len); |
| } |
| } |
| return zret; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_hierarchy |
| |
| Retrieve the int pointed at by the buffer and treat as a |
| SquidHierarchyCode. Use this as an index into the local string |
| conversion tables and return the string equivalent to the enum. |
| Advance the buffer pointer. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_hierarchy(char **buf, char *dest, int len, Ptr<LogFieldAliasMap> map) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "INVALID_CODE")); |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_finish_status |
| |
| Retrieve the int pointed at by the buffer and treat as a finish code. |
| Use the enum as an index into a string table and return the string equiv |
| of the enum. Advance the pointer. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_finish_status(char **buf, char *dest, int len, Ptr<LogFieldAliasMap> map) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "UNKNOWN_FINISH_CODE")); |
| } |
| |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_cache_code |
| |
| Retrieve the int pointed at by the buffer and treat as a SquidLogCode. |
| Use this to index into the local string tables and return the string |
| equiv of the enum. Advance the pointer. |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_cache_code(char **buf, char *dest, int len, Ptr<LogFieldAliasMap> map) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "ERROR_UNKNOWN")); |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogAccess::unmarshal_entry_type |
| -------------------------------------------------------------------------*/ |
| |
| int |
| LogAccess::unmarshal_entry_type(char **buf, char *dest, int len, Ptr<LogFieldAliasMap> map) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "UNKNOWN_ENTRY_TYPE")); |
| } |
| |
| int |
| LogAccess::unmarshal_cache_write_code(char **buf, char *dest, int len, Ptr<LogFieldAliasMap> map) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| return (LogAccess::unmarshal_with_map(unmarshal_int(buf), dest, len, map, "UNKNOWN_CACHE_WRITE_CODE")); |
| } |
| |
| int |
| LogAccess::unmarshal_record(char **buf, char *dest, int len) |
| { |
| ink_assert(buf != NULL); |
| ink_assert(*buf != NULL); |
| ink_assert(dest != NULL); |
| |
| char *val_buf = *buf; |
| int val_len = (int)::strlen(val_buf); |
| *buf += MARSHAL_RECORD_LENGTH; // this is how it was stored |
| if (val_len < len) { |
| memcpy(dest, val_buf, val_len); |
| return val_len; |
| } |
| return -1; |
| } |
| |
| /*------------------------------------------------------------------------- |
| resolve_logfield_string |
| |
| This function resolves the given custom log format string using the given |
| LogAccess context and returns the resulting string, which is ats_malloc'd. |
| The caller is responsible for ats_free'ing the return result. If there are |
| any problems, NULL is returned. |
| -------------------------------------------------------------------------*/ |
| char * |
| resolve_logfield_string(LogAccess *context, const char *format_str) |
| { |
| if (!context) { |
| Debug("log-resolve", "No context to resolve?"); |
| return NULL; |
| } |
| |
| if (!format_str) { |
| Debug("log-resolve", "No format to resolve?"); |
| return NULL; |
| } |
| |
| Debug("log-resolve", "Resolving: %s", format_str); |
| |
| // |
| // Divide the format string into two parts: one for the printf-style |
| // string and one for the symbols. |
| // |
| char *printf_str = NULL; |
| char *fields_str = NULL; |
| int n_fields = LogFormat::parse_format_string(format_str, &printf_str, &fields_str); |
| |
| // |
| // Perhaps there were no fields to resolve? Then just return the |
| // format_str. Nothing to free here either. |
| // |
| if (!n_fields) { |
| Debug("log-resolve", "No fields found; returning copy of format_str"); |
| ats_free(printf_str); |
| ats_free(fields_str); |
| return ats_strdup(format_str); |
| } |
| |
| Debug("log-resolve", "%d fields: %s", n_fields, fields_str); |
| Debug("log-resolve", "printf string: %s", printf_str); |
| |
| LogFieldList fields; |
| bool contains_aggregates; |
| int field_count = LogFormat::parse_symbol_string(fields_str, &fields, &contains_aggregates); |
| |
| if (field_count != n_fields) { |
| Error("format_str contains %d invalid field symbols", n_fields - field_count); |
| ats_free(printf_str); |
| ats_free(fields_str); |
| return NULL; |
| } |
| // |
| // Ok, now marshal the data out of the LogAccess object and into a |
| // temporary storage buffer. Make sure the LogAccess context is |
| // initialized first. |
| // |
| Debug("log-resolve", "Marshaling data from LogAccess into buffer ..."); |
| context->init(); |
| unsigned bytes_needed = fields.marshal_len(context); |
| char *buf = (char *) ats_malloc(bytes_needed); |
| unsigned bytes_used = fields.marshal(context, buf); |
| |
| ink_assert(bytes_needed == bytes_used); |
| Debug("log-resolve", " %u bytes marshalled", bytes_used); |
| |
| // |
| // Now we can "unmarshal" the data from the buffer into a string, |
| // combining it with the data from the printf string. The problem is, |
| // we're not sure how much space it will take when it's unmarshalled. |
| // So, we'll just guess. |
| // |
| char *result = (char *) ats_malloc(8192); |
| unsigned bytes_resolved = LogBuffer::resolve_custom_entry(&fields, printf_str, buf, result, |
| 8191, LogUtils::timestamp(), 0, |
| LOG_SEGMENT_VERSION); |
| ink_assert(bytes_resolved < 8192); |
| |
| if (!bytes_resolved) { |
| ats_free(result); |
| result = NULL; |
| } else |
| result[bytes_resolved] = 0; // NULL terminate |
| |
| ats_free(printf_str); |
| ats_free(fields_str); |
| ats_free(buf); |
| |
| return result; |
| } |