| /** @file |
| |
| A brief file description |
| |
| @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. |
| */ |
| |
| /*************************************************************************** |
| LogHost.cc |
| |
| |
| ***************************************************************************/ |
| #include "ink_unused.h" |
| |
| #include "ink_platform.h" |
| #include "Resource.h" |
| #include "Error.h" |
| |
| #include "LogUtils.h" |
| #include "LogSock.h" |
| #include "LogField.h" |
| #include "LogFile.h" |
| #include "LogFormat.h" |
| #include "LogBuffer.h" |
| #include "LogHost.h" |
| #include "LogObject.h" |
| #include "LogConfig.h" |
| #include "Log.h" |
| |
| #if defined(IOCORE_LOG_COLLATION) |
| #include "LogCollationClientSM.h" |
| #endif |
| |
| #define PING true |
| #define NOPING false |
| |
| /*------------------------------------------------------------------------- |
| LogHost |
| -------------------------------------------------------------------------*/ |
| |
| LogHost::LogHost(char *object_filename, inku64 object_signature) |
| : |
| m_object_filename(xstrdup(object_filename)) |
| , |
| m_object_signature(object_signature) |
| , |
| m_ip(0) |
| , |
| m_ipstr(NULL) |
| , |
| m_name(NULL) |
| , |
| m_port(0) |
| , |
| m_sock(NULL) |
| , |
| m_sock_fd(-1) |
| , |
| m_connected(false) |
| , |
| m_orphan_file(NULL) |
| #if defined (IOCORE_LOG_COLLATION) |
| , |
| m_log_collation_client_sm(NULL) |
| #endif |
| { |
| } |
| |
| LogHost::LogHost(const LogHost & rhs) |
| : |
| m_object_filename(xstrdup(rhs.m_object_filename)) |
| , |
| m_object_signature(rhs.m_object_signature) |
| , |
| m_ip(rhs.m_ip) |
| , |
| m_ipstr(xstrdup(rhs.m_ipstr)) |
| , |
| m_name(xstrdup(rhs.m_name)) |
| , |
| m_port(rhs.m_port) |
| , |
| m_sock(NULL) |
| , |
| m_sock_fd(-1) |
| , |
| m_connected(false) |
| , |
| m_orphan_file(NULL) |
| #if defined (IOCORE_LOG_COLLATION) |
| , |
| m_log_collation_client_sm(NULL) |
| #endif |
| { |
| create_orphan_LogFile_object(); |
| } |
| |
| LogHost::~LogHost() |
| { |
| clear(); |
| xfree(m_object_filename); |
| } |
| |
| // |
| // There are 3 ways to establish a LogHost: |
| // - by "hostname:port" or IP:port", where IP is a string of the |
| // form "xxx.xxx.xxx.xxx". |
| // - by specifying a hostname and a port (as separate arguments). |
| // - by specifying an ip and a port (as separate arguments). |
| // |
| |
| int |
| LogHost::set_name_port(char *hostname, unsigned int pt) |
| { |
| if (!hostname || hostname[0] == 0) { |
| Note("Cannot establish LogHost with NULL hostname"); |
| return 1; |
| } |
| |
| clear(); // remove all previous state for this LogHost |
| |
| m_ip = 0; // make sure ip is 0 for iocore |
| #if !defined(IOCORE_LOG_COLLATION) |
| m_ip = LogUtils::ip_from_host(hostname); |
| m_ipstr = (char *) xmalloc(32); |
| LogUtils::ip_to_str(m_ip, m_ipstr, 32); |
| #endif |
| m_name = xstrdup(hostname); |
| m_port = pt; |
| |
| Debug("log2-host", "LogHost established as %s:%u", name(), port()); |
| |
| create_orphan_LogFile_object(); |
| return 0; |
| } |
| |
| int |
| LogHost::set_ipstr_port(char *ipstr, unsigned int pt) |
| { |
| if (!ipstr || ipstr[0] == 0) { |
| Note("Cannot establish LogHost with NULL ipstr"); |
| return 1; |
| } |
| |
| clear(); // remove all previous state for this LogHost |
| |
| m_ip = htonl(LogUtils::str_to_ip(ipstr)); |
| m_ipstr = xstrdup(ipstr); |
| m_name = xstrdup(ipstr); |
| m_port = pt; |
| |
| Debug("log2-host", "LogHost established as %s:%u", name(), port()); |
| |
| create_orphan_LogFile_object(); |
| return 0; |
| } |
| |
| int |
| LogHost::set_name_or_ipstr(char *name_or_ip) |
| { |
| int retVal = 1; |
| |
| if (name_or_ip && name_or_ip[0] != 0) { |
| SimpleTokenizer tok(name_or_ip, ':'); |
| char *n = tok.getNext(); |
| if (n) { |
| char *p = tok.getNext(); |
| unsigned int port = (p ? (unsigned int) atoi(p) : Log::config->collation_port); |
| |
| if (LogUtils::valid_ipstr_format(n)) { |
| retVal = set_ipstr_port(n, port); |
| } else { |
| retVal = set_name_port(n, port); |
| } |
| } |
| } |
| return retVal; |
| } |
| |
| bool LogHost::connected(bool ping) |
| { |
| if (m_connected && m_sock && m_sock_fd >= 0) { |
| if (m_sock->is_connected(m_sock_fd, ping)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool LogHost::connect() |
| { |
| if (!m_ip) { |
| Note("Cannot connect to LogHost; host IP has not been established"); |
| return false; |
| } |
| |
| if (connected(PING)) { |
| return true; |
| } |
| |
| Debug("log2-host", "Connecting to LogHost %s:%u", name(), port()); |
| |
| disconnect(); // make sure connection members are initialized |
| |
| if (m_sock == NULL) { |
| m_sock = NEW(new LogSock()); |
| ink_assert(m_sock != NULL); |
| } |
| m_sock_fd = m_sock->connect(m_ip, m_port); |
| if (m_sock_fd < 0) { |
| Note("Connection to LogHost %s:%u failed", name(), port()); |
| return false; |
| } |
| m_connected = true; |
| |
| if (!authenticated()) { |
| Note("Authentication to LogHost %s:%u failed", name(), port()); |
| disconnect(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void |
| LogHost::disconnect() |
| { |
| if (m_sock && m_sock_fd >= 0) { |
| m_sock->close(m_sock_fd); |
| m_sock_fd = -1; |
| } |
| m_connected = false; |
| } |
| |
| int |
| LogHost::write(LogBuffer * lb, size_t * to_disk, size_t * to_net, size_t * to_pipe) |
| { |
| if (lb == NULL) { |
| Note("Cannot write LogBuffer to LogHost %s; LogBuffer is NULL", name()); |
| return -1; |
| } |
| LogBufferHeader *buffer_header = lb->header(); |
| if (buffer_header == NULL) { |
| Note("Cannot write LogBuffer to LogHost %s; LogBufferHeader is NULL", name()); |
| return -1; |
| } |
| if (buffer_header->entry_count == 0) { |
| // no bytes to write |
| return 0; |
| } |
| #if !defined(IOCORE_LOG_COLLATION) |
| |
| // make sure we're connected & authenticated |
| |
| if (!connected(NOPING)) { |
| if (!connect()) { |
| Note("Cannot write LogBuffer to LogHost %s; not connected", name()); |
| return orphan_write(lb); |
| } |
| } |
| // try sending the logbuffer |
| |
| int bytes_to_send, bytes_sent; |
| bytes_to_send = buffer_header->byte_count; |
| lb->convert_to_network_order(); |
| bytes_sent = m_sock->write(m_sock_fd, buffer_header, bytes_to_send); |
| if (bytes_to_send != bytes_sent) { |
| Note("Bad write to LogHost %s; bad send count %d/%d", name(), bytes_sent, bytes_to_send); |
| disconnect(); |
| lb->convert_to_host_order(); |
| return orphan_write(lb); |
| } |
| |
| Debug("log2-host", "%d bytes sent to LogHost %s:%u", bytes_sent, name(), port()); |
| // BUGBUG:: fix this, Log Collation should work on NT as well |
| SUM_DYN_STAT(log2_stat_bytes_sent_to_network_stat, bytes_sent); |
| return bytes_sent; |
| |
| #else // !defined(IOCORE_LOG_COLLATION) |
| |
| // make a copy of our log_buffer |
| int buffer_header_size = buffer_header->byte_count; |
| LogBufferHeader *buffer_header_copy = (LogBufferHeader *) NEW(new char[buffer_header_size]); |
| ink_assert(buffer_header_copy != NULL); |
| |
| memcpy(buffer_header_copy, buffer_header, buffer_header_size); |
| LogBuffer *lb_copy = NEW(new LogBuffer(lb->get_owner(), |
| buffer_header_copy)); |
| ink_assert(lb_copy != NULL); |
| |
| // create a new collation client if necessary |
| if (m_log_collation_client_sm == NULL) { |
| m_log_collation_client_sm = NEW(new LogCollationClientSM(this)); |
| ink_assert(m_log_collation_client_sm != NULL); |
| } |
| // send log_buffer; orphan if necessary |
| int bytes_sent = m_log_collation_client_sm->send(lb_copy); |
| if (bytes_sent <= 0) { |
| #ifndef TS_MICRO |
| bytes_sent = orphan_write_and_delete(lb_copy, to_disk); |
| #if defined(LOG_BUFFER_TRACKING) |
| Debug("log2-buftrak", "[%d]LogHost::write - orphan write complete", lb_copy->header()->id); |
| #endif // defined(LOG_BUFFER_TRACKING) |
| #else |
| Note("Starting dropping log buffer due to overloading"); |
| delete lb_copy; |
| lb_copy = 0; |
| #endif // TS_MICRO |
| } else { |
| if (to_net) { |
| *to_net += bytes_sent; |
| } |
| } |
| |
| return bytes_sent; |
| |
| #endif // !defined(IOCORE_LOG_COLLATION) |
| } |
| |
| void |
| LogHost::create_orphan_LogFile_object() |
| { |
| delete m_orphan_file; |
| |
| char *orphan_ext = "orphan"; |
| unsigned name_len = (unsigned) (strlen(m_object_filename) + strlen(name()) + strlen(orphan_ext) + 16); |
| char *name_buf = (char *) xmalloc(name_len); |
| ink_assert(name_buf != NULL); |
| // NT: replace ':'s with '-'s. This change is necessary because |
| // NT doesn't like filenames with ':'s in them. ^_^ |
| ink_snprintf(name_buf, name_len, "%s%s%s-%u.%s", |
| m_object_filename, LOGFILE_SEPARATOR_STRING, name(), port(), orphan_ext); |
| |
| // should check for conflicts with orphan filename |
| // |
| m_orphan_file = NEW(new LogFile(name_buf, NULL, ASCII_LOG, m_object_signature)); |
| ink_assert(m_orphan_file != NULL); |
| xfree(name_buf); |
| } |
| |
| #ifndef TS_MICRO |
| int |
| LogHost::orphan_write(LogBuffer * lb, size_t * to_file) |
| { |
| if (!Log::config->logging_space_exhausted) { |
| Debug("log2-host", "Sending LogBuffer to orphan file %s", m_orphan_file->get_name()); |
| return m_orphan_file->write(lb, to_file); |
| } else { |
| return 0; // nothing written |
| } |
| } |
| |
| int |
| LogHost::orphan_write_and_delete(LogBuffer * lb, size_t * to_disk) |
| { |
| int bytes = orphan_write(lb, to_disk); |
| // done with the buffer, delete it |
| delete lb; |
| lb = 0; |
| return bytes; |
| } |
| #endif // TS_MICRO |
| |
| void |
| LogHost::display(FILE * fd) |
| { |
| fprintf(fd, "LogHost: %s:%u, %s\n", name(), port(), (connected(NOPING)) ? "connected" : "not connected"); |
| } |
| |
| void |
| LogHost::clear() |
| { |
| // close an established connection and clear the state of this host |
| |
| disconnect(); |
| |
| if (m_name) |
| xfree(m_name); |
| if (m_ipstr) |
| xfree(m_ipstr); |
| if (m_sock) |
| delete m_sock; |
| if (m_orphan_file) |
| delete m_orphan_file; |
| |
| m_ip = 0; |
| m_ipstr = NULL; |
| m_name = NULL; |
| m_port = 0; |
| m_sock = NULL; |
| m_sock_fd = -1; |
| m_connected = false; |
| m_orphan_file = NULL; |
| } |
| |
| bool LogHost::authenticated() |
| { |
| if (!connected(NOPING)) { |
| Note("Cannot authenticate LogHost %s; not connected", name()); |
| return false; |
| } |
| |
| Debug("log2-host", "Authenticating LogHost %s ...", name()); |
| char * |
| auth_key = Log::config->collation_secret; |
| unsigned |
| auth_key_len = (unsigned)::strlen(auth_key) + 1; // incl null |
| int |
| bytes = m_sock->write(m_sock_fd, auth_key, auth_key_len); |
| if ((unsigned) bytes != auth_key_len) { |
| Debug("log2-host", "... bad write on authenticate"); |
| return false; |
| } |
| |
| Debug("log2-host", "... authenticated"); |
| return true; |
| } |
| |
| /*------------------------------------------------------------------------- |
| LogHostList |
| -------------------------------------------------------------------------*/ |
| |
| LogHostList::LogHostList() |
| { |
| } |
| |
| LogHostList::~LogHostList() |
| { |
| clear(); |
| } |
| |
| void |
| LogHostList::add(LogHost * object, bool copy) |
| { |
| ink_assert(object != NULL); |
| if (copy) { |
| m_host_list.enqueue(NEW(new LogHost(*object))); |
| } else { |
| m_host_list.enqueue(object); |
| } |
| } |
| |
| unsigned |
| LogHostList::count() |
| { |
| unsigned cnt = 0; |
| for (LogHost * host = first(); host; host = next(host)) { |
| cnt++; |
| } |
| return cnt; |
| } |
| |
| void |
| LogHostList::clear() |
| { |
| LogHost *host; |
| while ((host = m_host_list.dequeue())) { |
| delete host; |
| } |
| } |
| |
| int |
| LogHostList::write(LogBuffer * lb, size_t * to_disk, size_t * to_net, size_t * to_pipe) |
| { |
| int total_bytes = 0; |
| for (LogHost * host = first(); host; host = next(host)) { |
| int bytes = host->write(lb, to_disk, to_net, to_pipe); |
| if (bytes > 0) |
| total_bytes += bytes; |
| } |
| return total_bytes; |
| } |
| |
| void |
| LogHostList::display(FILE * fd) |
| { |
| for (LogHost * host = first(); host; host = next(host)) { |
| host->display(fd); |
| } |
| } |
| |
| bool LogHostList::operator==(LogHostList & rhs) |
| { |
| LogHost * |
| host; |
| for (host = first(); host; host = next(host)) { |
| LogHost * |
| rhs_host; |
| for (rhs_host = rhs.first(); rhs_host; rhs_host = next(host)) { |
| if ((host->port() == rhs_host->port() && |
| (host->ip() && rhs_host->ip() && |
| (host->ip() == rhs_host->ip()))) || |
| (host->name() && rhs_host->name() && |
| (strcmp(host->name(), rhs_host->name()) == 0)) || |
| (host->ipstr() && rhs_host->ipstr() && (strcmp(host->ipstr(), rhs_host->ipstr()) == 0))) { |
| break; |
| } |
| } |
| if (rhs_host == NULL) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| int |
| LogHostList::do_filesystem_checks() |
| { |
| for (LogHost * host = first(); host; host = next(host)) { |
| if (host->do_filesystem_checks() < 0) { |
| return -1; |
| } |
| } |
| return 0; |
| } |