| /** @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. |
| */ |
| |
| /* |
| * |
| * LocalManager.cc |
| * - The Local Manager process of the management system. |
| * - The main loop has been migrated to Main.cc |
| * |
| * |
| */ |
| |
| #include "ink_unused.h" /* MAGIC_EDITING_TAG */ |
| |
| #include "ink_platform.h" |
| #include "inktomi++.h" |
| #include "Compatability.h" |
| #include "LocalManager.h" |
| #include "NTDefs.h" |
| #include "WebReconfig.h" |
| #include "MgmtSocket.h" |
| |
| int bindProxyPort(int, in_addr_t, int); |
| |
| bool |
| LocalManager::SetForDup(void *hIOCPort, long lTProcId, void *hTh) |
| { |
| return true; |
| } |
| |
| |
| |
| void |
| LocalManager::mgmtCleanup() |
| { |
| ink_close_socket(process_server_sockfd); |
| |
| // fix me for librecords |
| |
| if (virt_map) { |
| virt_map->rl_downAddrs(); // We are bailing done need to worry about table |
| } |
| #ifdef MGMT_USE_SYSLOG |
| closelog(); |
| #endif /* MGMT_USE_SYSLOG */ |
| return; |
| } /* End LocalManager::mgmtCleanup */ |
| |
| |
| void |
| LocalManager::mgmtShutdown(int status, bool mainThread) |
| { |
| if (mainThread) { |
| #ifdef USE_SNMP |
| if (snmp) { |
| snmp->shutdown(); |
| snmp = NULL; |
| } |
| #endif |
| |
| mgmt_log("[LocalManager::mgmtShutdown] Executing shutdown request.\n"); |
| processShutdown(mainThread); |
| |
| if (processRunning()) { |
| waitpid(watched_process_pid, &status, 0); |
| #if (HOST_OS == linux) |
| /* Avert race condition, wait for the thread to complete, |
| before getting one more restart process */ |
| /* Workaround for bugid INKqa10060 */ |
| mgmt_sleep_msec(1); |
| #endif |
| } |
| |
| mgmtCleanup(); |
| _exit(status); |
| } else { |
| mgmt_shutdown_outstanding = true; |
| } |
| return; |
| } /* End LocalManager::mgmtShutdown */ |
| |
| |
| void |
| LocalManager::processShutdown(bool mainThread) |
| { |
| /* 3com does not want these messages to be seen */ |
| mgmt_log("[LocalManager::processShutdown] Executing process shutdown request.\n"); |
| if (mainThread) { |
| sendMgmtMsgToProcesses(MGMT_EVENT_SHUTDOWN, "processShutdown[main]"); |
| } else { |
| signalEvent(MGMT_EVENT_SHUTDOWN, "processShutdown"); |
| } |
| return; |
| } /* End LocalManager::processShutdown */ |
| |
| |
| void |
| LocalManager::processRestart() |
| { |
| mgmt_log("[LocalManager::processRestart] Executing process restart request.\n"); |
| signalEvent(MGMT_EVENT_RESTART, "processRestart"); |
| return; |
| } /* End LocalManager::processRestart */ |
| |
| |
| void |
| LocalManager::processBounce() |
| { |
| mgmt_log("[LocalManager::processBounce] Executing process bounce request.\n"); |
| signalEvent(MGMT_EVENT_BOUNCE, "processBounce"); |
| return; |
| } /* End LocalManager::processBounce */ |
| |
| void |
| LocalManager::rollLogFiles() |
| { |
| mgmt_log("[LocalManager::rollLogFiles] Log files are being rolled.\n"); |
| signalEvent(MGMT_EVENT_ROLL_LOG_FILES, "rollLogs"); |
| return; |
| } |
| |
| char snap_filename[FILE_NAME_MAX+1] = "stats.snap"; |
| |
| void |
| LocalManager::clearStats() |
| { |
| char *statsPath; |
| char local_state_dir[FILE_NAME_MAX]; |
| char snap_file[FILE_NAME_MAX]; |
| struct stat s; |
| int err; |
| |
| REC_ReadConfigString(local_state_dir, "proxy.config.local_state_dir", FILE_NAME_MAX); |
| if ((err = stat(local_state_dir, &s)) < 0) { |
| Warning("Unable to stat() local state directory '%s': %d %d, %s", local_state_dir, err, errno, strerror(errno)); |
| Warning(" Please set 'proxy.config.local_state_dir' to allow statistics collection"); |
| } |
| REC_ReadConfigString(snap_file, "proxy.config.stats.snap_file", FILE_NAME_MAX); |
| snprintf(snap_filename, sizeof(snap_filename), "%s%s%s", local_state_dir, |
| DIR_SEP, snap_file); |
| |
| // Clear our records and then send the signal. There is a race condition |
| // here where our stats could get re-updated from the proxy |
| // before the proxy clears them, but this should be rare. |
| // |
| // Doing things in the opposite order prevents that race |
| // but excerbates the race between the node and cluster |
| // stats getting cleared by progation of clearing the |
| // cluster stats |
| // |
| NOWARN_UNUSED(snap_filename); |
| |
| RecResetStatRecord(); |
| |
| // If the proxy is not running, sending the signal does |
| // not do anything. Remove the stats file to make sure |
| // that operation works even when the proxy is off |
| // |
| if (this->proxy_running == 0) { |
| statsPath = REC_RAW_STATS_DIR REC_RAW_STATS_FILE; |
| if (unlink(statsPath) < 0) { |
| if (errno != ENOENT) { |
| mgmt_log(stderr, "[LocalManager::clearStats] Unlink of %s failed : %s\n", REC_RAW_STATS_FILE, strerror(errno)); |
| } |
| } |
| } |
| |
| } /* End LocalManager::clearStats */ |
| |
| // void LocalManager::syslogThrInit() |
| // |
| // On the DEC, syslog is per thread. This function |
| // allows a thread to init syslog with the appropriate |
| // configuration |
| // |
| void |
| LocalManager::syslogThrInit() |
| { |
| } /* End LocalManager::syslogThrInit */ |
| |
| // bool LocalManager::clusterOk() |
| // |
| // Returns false if the proxy has been up for more than |
| // 30 seconds but is not reporting that it has clustered |
| // with all the nodes in cluster.config |
| // |
| // Otherwise returns true |
| // |
| bool |
| LocalManager::clusterOk() |
| { |
| bool found = true; |
| bool result = true; |
| |
| if (processRunning() == true && time(NULL) > (this->proxy_started_at + 30) |
| && this->ccom->alive_peers_count + 1 != REC_readInteger("proxy.process.cluster.nodes", &found)) { |
| result = false; |
| } |
| |
| ink_assert(found); |
| return result; |
| } /* End LocalManager::clusterOk */ |
| |
| bool |
| LocalManager::processRunning() |
| { |
| if (watched_process_fd != -1 && watched_process_pid != -1) { |
| return true; |
| } else { |
| return false; |
| } |
| } /* End LocalManager::processRunning */ |
| |
| LocalManager::LocalManager(char *mpath, LMRecords * rd, bool proxy_on): |
| BaseManager(), run_proxy(proxy_on), record_data(rd) |
| { |
| bool found; |
| struct stat s; |
| int err; |
| #ifdef MGMT_USE_SYSLOG |
| syslog_facility = 0; |
| #endif |
| |
| ccom = NULL; |
| proxy_started_at = -1; |
| proxy_launch_count = 0; |
| manager_started_at = time(NULL); |
| proxy_launch_outstanding = false; |
| mgmt_shutdown_outstanding = false; |
| proxy_running = 0; |
| REC_setInteger("proxy.node.proxy_running", 0); |
| mgmt_sync_key = REC_readInteger("proxy.config.lm.sem_id", &found); |
| if (!found || mgmt_sync_key <= 0) { |
| mgmt_log("Bad or missing proxy.config.lm.sem_id value; using default id %d\n", MGMT_SEMID_DEFAULT); |
| mgmt_sync_key = MGMT_SEMID_DEFAULT; |
| } |
| ink_strncpy(pserver_path, system_local_state_dir, sizeof(pserver_path)); |
| |
| virt_map = NULL; |
| |
| |
| for (int i = 0; i < MAX_PROXY_SERVER_PORTS; i++) { |
| proxy_server_port[i] = proxy_server_fd[i] = -1; |
| memset((void *) proxy_server_port_attributes[i], 0, MAX_ATTR_LEN); |
| } |
| |
| int pnum = 0; |
| RecInt http_enabled = REC_readInteger("proxy.config.http.enabled", &found); |
| ink_debug_assert(found); |
| if (http_enabled && found) { |
| int port = (int) REC_readInteger("proxy.config.http.server_port", &found); |
| if (found) { |
| proxy_server_port[pnum] = port; |
| char *main_server_port_attributes = (char *) REC_readString("proxy.config.http.server_port_attr", &found); |
| ink_strncpy((char *) proxy_server_port_attributes[pnum], |
| main_server_port_attributes, sizeof(proxy_server_port_attributes[pnum])); |
| xfree(main_server_port_attributes); |
| pnum++; |
| } |
| } |
| // Check to see if we are running QT |
| RecInt qt_enabled = REC_readInteger("proxy.config.qt.enabled", &found); |
| ink_assert(found); |
| RecInt rni_enabled = REC_readInteger("proxy.config.rni.enabled", &found); |
| ink_assert(found); |
| if (qt_enabled || rni_enabled) { |
| // Get the QT port |
| RecInt qt_port = REC_readInteger("proxy.config.mixt.rtsp_proxy_port", &found); |
| ink_assert(found); |
| if (found) { |
| proxy_server_port[pnum] = qt_port; |
| ink_strncpy((char *) proxy_server_port_attributes[pnum], "Q", sizeof(proxy_server_port_attributes[pnum])); |
| pnum++; |
| } |
| } |
| |
| // Check to see if we are running SSL term |
| RecInt ssl_term_enabled = REC_readInteger("proxy.config.ssl.enabled", &found); |
| ink_assert(found); |
| if (found && ssl_term_enabled) { |
| // Get the SSL port |
| RecInt ssl_term_port = REC_readInteger("proxy.config.ssl.server_port", &found); |
| ink_assert(found); |
| if (found) { |
| proxy_server_port[pnum] = ssl_term_port; |
| ink_strncpy((char *) proxy_server_port_attributes[pnum], "S", sizeof(proxy_server_port_attributes[pnum])); |
| pnum++; |
| } |
| } |
| // Check to see if we are running FTP |
| RecInt ftp_enabled = REC_readInteger("proxy.config.ftp.ftp_enabled", &found); |
| ink_assert(found); |
| if (found && ftp_enabled) { |
| // Get the FTP port |
| RecInt ftp_port = REC_readInteger("proxy.config.ftp.proxy_server_port", &found); |
| ink_assert(found); |
| if (found) { |
| proxy_server_port[pnum] = (int) ftp_port; |
| ink_strncpy((char *) proxy_server_port_attributes[pnum], "F", sizeof(proxy_server_port_attributes[pnum])); |
| pnum++; |
| } |
| } |
| // Check to see if we are running DNS proxy |
| RecInt dns_proxy_enabled = REC_readInteger("proxy.config.dns.proxy.enabled", &found); |
| ink_assert(found); |
| if (found && dns_proxy_enabled) { |
| // Get the DNS cache port |
| RecInt dns_proxy_port = REC_readInteger("proxy.config.dns.proxy_port", &found); |
| ink_assert(found); |
| if (found) { |
| proxy_server_port[pnum] = (int) dns_proxy_port; |
| ink_strncpy((char *) proxy_server_port_attributes[pnum], "D", sizeof(proxy_server_port_attributes[pnum])); |
| pnum++; |
| } |
| } |
| // Read other ports to be listened on |
| char *proxy_server_other_ports = REC_readString("proxy.config.http.server_other_ports", &found); |
| if (proxy_server_other_ports) { |
| char *last, *cport; |
| |
| cport = ink_strtok_r(proxy_server_other_ports, " ", &last); |
| for (; pnum < MAX_PROXY_SERVER_PORTS && cport; pnum++) { |
| char *attr = "X"; |
| |
| for (int j = 0; cport[j]; j++) { |
| if (cport[j] == ':') { |
| cport[j] = '\0'; |
| attr = &cport[j + 1]; |
| } |
| } |
| |
| int port_no = atoi(cport); |
| |
| proxy_server_port[pnum] = port_no; |
| ink_strncpy((char *) proxy_server_port_attributes[pnum], attr, sizeof(proxy_server_port_attributes[pnum])); |
| |
| Debug("lm", "[LocalManager::LocalManager] Adding port (%s, %d, '%s')\n", cport, port_no, attr); |
| cport = ink_strtok_r(NULL, " ", &last); |
| } |
| |
| if (pnum == MAX_PROXY_SERVER_PORTS && cport) { |
| Debug("lm", "[LocalManager::LocalManager] Unable to listen on all other ports," |
| " max number of other ports exceeded(max == %d)\n", MAX_PROXY_SERVER_PORTS); |
| } |
| xfree(proxy_server_other_ports); |
| } |
| // Bind proxy ports to incoming_ip_to_bind |
| char *incoming_ip_to_bind_str = REC_readString("proxy.local.incoming_ip_to_bind", &found); |
| if (found && incoming_ip_to_bind_str != NULL) { |
| proxy_server_incoming_ip_to_bind = inet_addr(incoming_ip_to_bind_str); |
| } else { |
| proxy_server_incoming_ip_to_bind = htonl(INADDR_ANY); |
| } |
| config_path = REC_readString("proxy.config.config_dir", &found); |
| if ((err = stat(config_path, &s)) < 0) { |
| xfree(config_path); |
| config_path = xstrdup(system_config_directory); |
| if ((err = stat(config_path, &s)) < 0) { |
| mgmt_elog("[LocalManager::LocalManager] unable to stat() directory '%s': %d %d, %s\n", |
| config_path, err, errno, strerror(errno)); |
| mgmt_fatal("[LocalManager::LocalManager] please set config path via command line '-path <path>' or 'proxy.config.config_dir' \n"); |
| } |
| } |
| |
| bin_path = REC_readString("proxy.config.bin_path", &found); |
| process_server_timeout_secs = REC_readInteger("proxy.config.lm.pserver_timeout_secs", &found); |
| process_server_timeout_msecs = REC_readInteger("proxy.config.lm.pserver_timeout_msecs", &found); |
| proxy_name = REC_readString("proxy.config.proxy_name", &found); |
| proxy_binary = REC_readString("proxy.config.proxy_binary", &found); |
| proxy_options = REC_readString("proxy.config.proxy_binary_opts", &found); |
| env_prep = REC_readString("proxy.config.env_prep", &found); |
| |
| const size_t absolute_proxy_binary_size = sizeof(char) * (strlen(system_root_dir) + strlen(bin_path) + strlen(proxy_binary)) + 2; |
| absolute_proxy_binary = (char *) xmalloc(absolute_proxy_binary_size); |
| snprintf(absolute_proxy_binary, absolute_proxy_binary_size, "%s%s%s", bin_path, DIR_SEP, proxy_binary); |
| |
| if ((err = stat(absolute_proxy_binary, &s)) < 0) { |
| // Try 'root_dir/bin_path' directory |
| snprintf(absolute_proxy_binary, absolute_proxy_binary_size, "%s%s%s%s", system_root_dir,bin_path, DIR_SEP, proxy_binary); |
| // coverity[fs_check_call] |
| if ((err = stat(absolute_proxy_binary, &s)) < 0) { |
| mgmt_elog("[LocalManager::LocalManager] Unable to find '%s': %d %d, %s\n", |
| absolute_proxy_binary, err, errno, strerror(errno)); |
| mgmt_fatal("[LocalManager::LocalManager] please set bin path 'proxy.config.bin_path' \n"); |
| } |
| } |
| |
| internal_ticker = 0; |
| |
| watched_process_pid = -1; |
| |
| process_server_sockfd = -1; |
| watched_process_fd = -1; |
| proxy_launch_pid = -1; |
| |
| return; |
| } /* End LocalManager::LocalManager */ |
| |
| void |
| LocalManager::initAlarm() |
| { |
| alarm_keeper = new Alarms(); |
| } |
| |
| /* |
| * initCCom(...) |
| * Function initializes cluster communication structure held by local manager. |
| */ |
| void |
| LocalManager::initCCom(int port, char *addr, int sport) |
| { |
| bool found; |
| struct in_addr cluster_addr; // ip addr of the cluster interface |
| char *clusterAddrStr; // cluster ip addr as a String |
| char *intrName; // Name of the interface we are to use |
| char hostname[1024]; // hostname of this machine |
| const char envVar[] = "PROXY_CLUSTER_ADDR="; |
| char *envBuf; |
| |
| if (gethostname(hostname, 1024) < 0) { |
| mgmt_fatal(stderr, "[LocalManager::initCCom] gethostname failed\n"); |
| } |
| // Fetch which interface we are using for clustering |
| intrName = REC_readString("proxy.config.cluster.ethernet_interface", &found); |
| ink_assert(intrName != NULL); |
| |
| found = mgmt_getAddrForIntr(intrName, &cluster_addr); |
| if (found == false) { |
| mgmt_log(stderr, "[LocalManager::initCCom] Unable to find network interface %s. Exiting...\n", intrName); |
| _exit(1); |
| } |
| |
| clusterAddrStr = inet_ntoa(cluster_addr); |
| Debug("ccom", "Cluster Interconnect is %s : %s\n", intrName, clusterAddrStr); |
| |
| // This an awful hack but I could not come up with a better way to |
| // pass the cluster address to the proxy |
| // Set an environment variable so the proxy can find out |
| // what the cluster address is. The reason we need this awful |
| // hack is that the proxy needs this info immediately at startup |
| // and it is different for every machine in the cluster so using |
| // a config variable will not work. |
| // The other options are to pass it on the command line to the proxy |
| // which would require a fair bit of code modification since |
| // what is passed right now is assumed to be static. The other |
| // is to write it to a separate file but that seems like a |
| // lot of trouble for a 16 character string |
| // Set the cluster ip addr variable so that proxy can read it |
| // and flush it to disk |
| const size_t envBuf_size = strlen(envVar) + strlen(clusterAddrStr) + 1; |
| envBuf = (char *) xmalloc(envBuf_size); |
| ink_strncpy(envBuf, envVar, envBuf_size); |
| strncat(envBuf, clusterAddrStr, envBuf_size - strlen(envBuf) - 1); |
| ink_release_assert(putenv(envBuf) == 0); |
| |
| ccom = new ClusterCom(cluster_addr.s_addr, hostname, port, addr, sport, pserver_path); |
| virt_map = new VMap(intrName, cluster_addr.s_addr, &lmgmt->ccom->mutex); |
| virt_map->downAddrs(); // Just to be safe |
| ccom->establishChannels(); |
| |
| if (intrName) { |
| xfree(intrName); |
| } |
| return; |
| } /* End LocalManager::initCCom */ |
| |
| /* |
| * initMgmtProcessServer() |
| * - On UNIX, this function sets up the server socket that proxy processes connect to. |
| * - On WIN32, named pipes are used instead. |
| */ |
| void |
| LocalManager::initMgmtProcessServer() |
| { |
| char fpath[1024]; |
| int servlen, one = 1; |
| struct sockaddr_un serv_addr; |
| |
| snprintf(fpath, sizeof(fpath), "%s/%s", pserver_path, LM_CONNECTION_SERVER); |
| #if (HOST_OS == freebsd) |
| char ulpath[1024]; |
| strcpy(ulpath, fpath); |
| ulpath[strlen(fpath) - 1] = 0; |
| unlink(ulpath); |
| #else |
| unlink(fpath); |
| #endif |
| if ((process_server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { |
| mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to open socket exiting\n"); |
| } |
| |
| if (fcntl(process_server_sockfd, F_SETFD, 1) < 0) { |
| mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to set close-on-exec\n"); |
| } |
| |
| memset(&serv_addr, 0, sizeof(serv_addr)); |
| serv_addr.sun_family = AF_UNIX; |
| ink_strncpy(serv_addr.sun_path, fpath, sizeof(serv_addr.sun_path)); |
| servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); |
| |
| if (setsockopt(process_server_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) { |
| mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to set socket options.\n"); |
| } |
| |
| if ((bind(process_server_sockfd, (struct sockaddr *) &serv_addr, servlen)) < 0) { |
| mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to bind '%s' socket exiting\n", fpath); |
| } |
| |
| if ((listen(process_server_sockfd, 5)) < 0) { |
| mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to listen on socket exiting\n"); |
| } |
| |
| REC_setInteger("proxy.node.restarts.manager.start_time", manager_started_at); |
| } /* End LocalManager::initMgmtProcessServer */ |
| |
| /* |
| * pollMgmtProcessServer() |
| * - Function checks the mgmt process server for new processes |
| * and any requests sent from processes. It handles processes sent. |
| */ |
| void |
| LocalManager::pollMgmtProcessServer() |
| { |
| int num; |
| struct timeval timeout; |
| struct sockaddr_in clientAddr; |
| fd_set fdlist; |
| |
| while (1) { |
| |
| // poll only |
| timeout.tv_sec = process_server_timeout_secs; |
| timeout.tv_usec = process_server_timeout_msecs * 1000; |
| |
| FD_ZERO(&fdlist); |
| FD_SET(process_server_sockfd, &fdlist); |
| if (watched_process_fd != -1) { |
| FD_SET(watched_process_fd, &fdlist); |
| } |
| |
| num = mgmt_select(FD_SETSIZE, &fdlist, NULL, NULL, &timeout); |
| if (num == 0) { /* Have nothing */ |
| |
| break; |
| |
| } else if (num > 0) { /* Have something */ |
| |
| if (FD_ISSET(process_server_sockfd, &fdlist)) { /* New connection */ |
| int clientLen = sizeof(clientAddr); |
| int new_sockfd = mgmt_accept(process_server_sockfd, |
| (struct sockaddr *) &clientAddr, |
| &clientLen); |
| MgmtMessageHdr *mh; |
| int data_len; |
| |
| mgmt_log(stderr, "[LocalManager::pollMgmtProcessServer] New process connecting fd '%d'\n", new_sockfd); |
| |
| if (new_sockfd < 0) { |
| mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] ==> "); |
| } else if (!processRunning()) { |
| watched_process_fd = new_sockfd; |
| data_len = sizeof(mgmt_sync_key); |
| mh = (MgmtMessageHdr *) alloca(sizeof(MgmtMessageHdr) + data_len); |
| mh->msg_id = MGMT_EVENT_SYNC_KEY; |
| mh->data_len = data_len; |
| memcpy((char *) mh + sizeof(MgmtMessageHdr), &mgmt_sync_key, data_len); |
| if (mgmt_write_pipe(new_sockfd, (char *) mh, sizeof(MgmtMessageHdr) + data_len) <= 0) { |
| mgmt_elog("[LocalManager::pollMgmtProcessServer] Error writing sync key message!\n"); |
| ink_close_socket(new_sockfd); |
| watched_process_fd = watched_process_pid = -1; |
| } |
| } else { |
| ink_close_socket(new_sockfd); |
| } |
| --num; |
| } |
| |
| if (FD_ISSET(watched_process_fd, &fdlist)) { |
| int res; |
| MgmtMessageHdr mh_hdr; |
| MgmtMessageHdr *mh_full; |
| char *data_raw; |
| |
| // read the message |
| if ((res = mgmt_read_pipe(watched_process_fd, (char *) &mh_hdr, sizeof(MgmtMessageHdr))) > 0) { |
| mh_full = (MgmtMessageHdr *) alloca(sizeof(MgmtMessageHdr) + mh_hdr.data_len); |
| memcpy(mh_full, &mh_hdr, sizeof(MgmtMessageHdr)); |
| data_raw = (char *) mh_full + sizeof(MgmtMessageHdr); |
| if ((res = mgmt_read_pipe(watched_process_fd, data_raw, mh_hdr.data_len)) > 0) { |
| handleMgmtMsgFromProcesses(mh_full); |
| } else if (res < 0) { |
| mgmt_fatal("[LocalManager::pollMgmtProcessServer] Error in read (errno: %d)\n", -res); |
| } |
| } else if (res < 0) { |
| mgmt_fatal("[LocalManager::pollMgmtProcessServer] Error in read (errno: %d)\n", -res); |
| } |
| // handle EOF |
| if (res == 0) { |
| |
| int estatus; |
| pid_t tmp_pid = watched_process_pid; |
| |
| Debug("lm", "[LocalManager::pollMgmtProcessServer] Lost process EOF!\n"); |
| |
| ink_close_socket(watched_process_fd); |
| |
| waitpid(watched_process_pid, &estatus, 0); /* Reap child */ |
| if (WIFSIGNALED(estatus)) { |
| int sig = WTERMSIG(estatus); |
| mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] " |
| "Server Process terminated due to Sig %d: %s\n", sig, strsignal(sig)); |
| } |
| |
| // watched_process_fd = watched_process_pid = -1; |
| // record_data->removeExternalRecords(PROCESS, watched_process_pid); |
| |
| if (lmgmt->run_proxy) { |
| mgmt_elog("[Alarms::signalAlarm] Server Process was reset\n"); |
| lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PROCESS_DIED); |
| } else { |
| mgmt_log("[TrafficManager] Server process shutdown\n"); |
| } |
| |
| watched_process_fd = watched_process_pid = -1; |
| if (tmp_pid != -1) { /* Incremented after a pid: message is sent */ |
| proxy_running--; |
| } |
| proxy_started_at = -1; |
| REC_setInteger("proxy.node.proxy_running", 0); |
| } |
| |
| num--; |
| |
| } |
| ink_assert(num == 0); /* Invariant */ |
| |
| } else if (num < 0) { /* Error */ |
| mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] select failed or was interrupted (%d)\n", errno); |
| } |
| |
| } |
| } /* End LocalManager::pollMgmtProcessServer */ |
| |
| |
| void |
| LocalManager::handleMgmtMsgFromProcesses(MgmtMessageHdr * mh) |
| { |
| |
| |
| char *data_raw = (char *) mh + sizeof(MgmtMessageHdr); |
| switch (mh->msg_id) { |
| case MGMT_SIGNAL_PID: |
| watched_process_pid = *((pid_t *) data_raw); |
| lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PROCESS_BORN); |
| proxy_running++; |
| proxy_launch_pid = -1; |
| proxy_launch_outstanding = false; |
| REC_setInteger("proxy.node.proxy_running", 1); |
| break; |
| |
| case MGMT_SIGNAL_MACHINE_UP: |
| /* |
| { |
| struct in_addr addr; |
| addr.s_addr = *((unsigned int*)data_raw); |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PEER_BORN, inet_ntoa(addr)); |
| } |
| */ |
| break; |
| case MGMT_SIGNAL_MACHINE_DOWN: |
| /* |
| { |
| struct in_addr addr; |
| addr.s_addr = *((unsigned int*)data_raw); |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PEER_DIED, inet_ntoa(addr)); |
| } |
| */ |
| break; |
| |
| // FIX: This is very messy need to correlate mgmt signals and |
| // alarms better |
| case MGMT_SIGNAL_CONFIG_ERROR: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_CONFIG_ERROR, data_raw); |
| break; |
| case MGMT_SIGNAL_SYSTEM_ERROR: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_SYSTEM_ERROR, data_raw); |
| break; |
| case MGMT_SIGNAL_NNTP_ERROR: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_NNTP_ERROR, data_raw); |
| break; |
| case MGMT_SIGNAL_LOG_SPACE_CRISIS: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_LOG_SPACE_CRISIS, data_raw); |
| break; |
| case MGMT_SIGNAL_CACHE_ERROR: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_CACHE_ERROR, data_raw); |
| break; |
| case MGMT_SIGNAL_CACHE_WARNING: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_CACHE_WARNING, data_raw); |
| break; |
| case MGMT_SIGNAL_LOGGING_ERROR: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_LOGGING_ERROR, data_raw); |
| break; |
| case MGMT_SIGNAL_LOGGING_WARNING: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_LOGGING_WARNING, data_raw); |
| break; |
| case MGMT_SIGNAL_CONFIG_FILE_READ: |
| mgmt_log(stderr, "[LocalManager::handleMgmtMsgFromProcesses] File done '%d'\n", data_raw); |
| break; |
| case MGMT_SIGNAL_PLUGIN_CONFIG_REG: |
| { |
| char *at = strchr(data_raw, '\t'); |
| if (at == NULL) { |
| mgmt_elog(stderr, "[LocalManager::handleMgmtMsgFromProcesses] Invalid plugin config msg '%s'\n", data_raw); |
| } else { |
| *at = '\0'; |
| char *plugin_config_path = at + 1; |
| char *plugin_name = data_raw; |
| plugin_list.add(plugin_name, plugin_config_path); |
| } |
| break; |
| } |
| case MGMT_SIGNAL_PLUGIN_ADD_REC: |
| { |
| char var_name[256]; |
| char var_value[256]; |
| RecDataT data_type; |
| // data_type is an enum type, so cast to an int* to avoid warnings. /leif |
| // coverity[secure_coding] |
| if (sscanf(data_raw, "%255s %d %255s", var_name, (int *) &data_type, var_value) != 3) { |
| Debug("lm", "Warning: Bad data_type: %s", (char *) data_raw); |
| data_type = RECD_MAX; |
| } |
| switch (data_type) { |
| case RECD_COUNTER: |
| RecRegisterStatCounter(RECT_PLUGIN, var_name, ink_atoll(var_value), RECP_NULL); |
| break; |
| case RECD_INT: |
| RecRegisterStatInt(RECT_PLUGIN, var_name, ink_atoll(var_value), RECP_NULL); |
| break; |
| case RECD_LLONG: |
| RecRegisterStatLLong(RECT_PLUGIN, var_name, ink_atoll(var_value), RECP_NULL); |
| break; |
| case RECD_FLOAT: |
| RecRegisterStatFloat(RECT_PLUGIN, var_name, atof(var_value), RECP_NULL); |
| break; |
| case RECD_STRING: |
| RecRegisterStatString(RECT_PLUGIN, var_name, var_value, RECP_NULL); |
| break; |
| default: |
| break; |
| } |
| break; |
| } |
| case MGMT_SIGNAL_PLUGIN_SET_CONFIG: |
| { |
| char var_name[256]; |
| char var_value[256]; |
| MgmtType stype; |
| // stype is an enum type, so cast to an int* to avoid warnings. /leif |
| int tokens = sscanf(data_raw, "%255s %d %255s", var_name, (int *) &stype, var_value); |
| if (tokens != 3) { |
| stype = INVALID; |
| } |
| switch (stype) { |
| case INK_INT: |
| REC_setInteger(var_name, ink_atoll(var_value)); |
| break; |
| case INK_LLONG: |
| REC_setLLong(var_name, ink_atoll(var_value)); |
| break; |
| case INK_COUNTER: |
| case INK_FLOAT: |
| case INK_STRING: |
| case INVALID: |
| default: |
| mgmt_elog(stderr, |
| "[LocalManager::handleMgmtMsgFromProcesses] " "Invalid plugin set-config msg '%s'\n", data_raw); |
| break; |
| } |
| } |
| case MGMT_SIGNAL_LOG_FILES_ROLLED: |
| { |
| Debug("lm", "Rolling logs %s", (char *) data_raw); |
| break; |
| } |
| case MGMT_SIGNAL_LIBRECORDS: |
| if (mh->data_len > 0) { |
| executeMgmtCallback(MGMT_SIGNAL_LIBRECORDS, data_raw, mh->data_len); |
| } else { |
| executeMgmtCallback(MGMT_SIGNAL_LIBRECORDS, NULL, 0); |
| } |
| break; |
| // Congestion Control - begin |
| case MGMT_SIGNAL_HTTP_CONGESTED_SERVER: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_HTTP_CONGESTED_SERVER, data_raw); |
| break; |
| case MGMT_SIGNAL_HTTP_ALLEVIATED_SERVER: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_HTTP_ALLEVIATED_SERVER, data_raw); |
| break; |
| // Congestion Control - end |
| case MGMT_SIGNAL_FTP_ERROR: |
| alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_FTP_ERROR, data_raw); |
| break; |
| // Wireless plugin signal - begin |
| case INK_MGMT_SIGNAL_WDA_BILLING_CONNECTION_DIED: |
| alarm_keeper->signalAlarm(MGMT_ALARM_WDA_BILLING_CONNECTION_DIED, data_raw); |
| break; |
| case INK_MGMT_SIGNAL_WDA_BILLING_CORRUPTED_DATA: |
| alarm_keeper->signalAlarm(MGMT_ALARM_WDA_BILLING_CORRUPTED_DATA, data_raw); |
| break; |
| case INK_MGMT_SIGNAL_WDA_XF_ENGINE_DOWN: |
| alarm_keeper->signalAlarm(MGMT_ALARM_WDA_XF_ENGINE_DOWN, data_raw); |
| break; |
| case INK_MGMT_SIGNAL_WDA_RADIUS_CORRUPTED_PACKETS: |
| alarm_keeper->signalAlarm(MGMT_ALARM_WDA_RADIUS_CORRUPTED_PACKETS, data_raw); |
| break; |
| // Wireless plugin signal - end |
| case INK_MGMT_SIGNAL_SAC_SERVER_DOWN: |
| alarm_keeper->signalAlarm(MGMT_ALARM_SAC_SERVER_DOWN, data_raw); |
| break; |
| |
| default: |
| break; |
| } |
| |
| // #define MGMT_ALARM_ACC_ALARMS_START 200 |
| // #define MGMT_ALARM_ACC_ALARMS_END 299 |
| |
| if (mh->msg_id >= INK_MGMT_SIGNAL_ACC_ALARMS_START && mh->msg_id <= INK_MGMT_SIGNAL_ACC_ALARMS_END) { |
| alarm_keeper->signalAlarm(mh->msg_id, data_raw); |
| } |
| |
| } /* End LocalManager::handleMgmtMsgFromProcesses */ |
| |
| |
| void |
| LocalManager::sendMgmtMsgToProcesses(int msg_id, const char *data_str) |
| { |
| sendMgmtMsgToProcesses(msg_id, data_str, strlen(data_str) + 1); |
| return; |
| } |
| |
| |
| void |
| LocalManager::sendMgmtMsgToProcesses(int msg_id, const char *data_raw, int data_len) |
| { |
| MgmtMessageHdr *mh; |
| |
| mh = (MgmtMessageHdr *) alloca(sizeof(MgmtMessageHdr) + data_len); |
| mh->msg_id = msg_id; |
| mh->data_len = data_len; |
| memcpy((char *) mh + sizeof(MgmtMessageHdr), data_raw, data_len); |
| sendMgmtMsgToProcesses(mh); |
| return; |
| } /* End LocalManager::sendMgmtMsgToProcesses */ |
| |
| |
| void |
| LocalManager::sendMgmtMsgToProcesses(MgmtMessageHdr * mh) |
| { |
| switch (mh->msg_id) { |
| case MGMT_EVENT_SHUTDOWN:{ |
| run_proxy = false; |
| if (lmgmt->virt_map) { |
| lmgmt->virt_map->downAddrs(); /* Down all known addrs to be safe */ |
| } |
| for (int i = 0; i < MAX_PROXY_SERVER_PORTS; i++) { |
| |
| if (proxy_server_fd[i] != -1) { // Close the socket |
| ink_close_socket(proxy_server_fd[i]); |
| proxy_server_fd[i] = -1; |
| } |
| } |
| break; |
| } |
| case MGMT_EVENT_RESTART: |
| run_proxy = true; |
| listenForProxy(); |
| return; |
| case MGMT_EVENT_BOUNCE: /* Just bouncing the cluster, have it exit well restart */ |
| mh->msg_id = MGMT_EVENT_SHUTDOWN; |
| break; |
| case MGMT_EVENT_ROLL_LOG_FILES: |
| mgmt_log("[LocalManager::SendMgmtMsgsToProcesses]Event is being constructed .\n"); |
| break; |
| case MGMT_EVENT_CONFIG_FILE_UPDATE: |
| bool found; |
| char *fname; |
| Rollback *rb; |
| char *data_raw; |
| |
| data_raw = (char *) mh + sizeof(MgmtMessageHdr); |
| fname = REC_readString(data_raw, &found); |
| |
| RecT rec_type; |
| if (RecGetRecordType(data_raw, &rec_type) == REC_ERR_OKAY && rec_type == RECT_CONFIG) { |
| RecSetSyncRequired(data_raw); |
| } else { |
| mgmt_elog(stderr, "[LocalManager:sendMgmtMsgToProcesses] Unknown file change: '%s'\n", data_raw); |
| } |
| ink_assert(found); |
| if (!(configFiles->getRollbackObj(fname, &rb)) && |
| (strcmp(data_raw, "proxy.config.cluster.cluster_configuration") != 0) && |
| (strcmp(data_raw, "proxy.config.arm.acl_filename_master") != 0) && |
| (strcmp(data_raw, "proxy.config.body_factory.template_sets_dir") != 0)) { |
| mgmt_elog(stderr, "[LocalManager::sendMgmtMsgToProcesses] " |
| "Invalid 'data_raw' for MGMT_EVENT_CONFIG_FILE_UPDATE\n"); |
| ink_assert(false); |
| } |
| xfree(fname); |
| break; |
| } |
| |
| if (watched_process_fd != -1) { |
| if (mgmt_write_pipe(watched_process_fd, (char *) mh, sizeof(MgmtMessageHdr) + mh->data_len) <= 0) { |
| |
| // In case of Linux, sometimes when the TS dies, the connection between TS and TM |
| // is not closed properly. the socket does not receive an EOF. So, the TM does |
| // not detect that the connection and hence TS has gone down. Hence it still |
| // tries to send a message to TS, but encounters an error and enters here |
| // Also, ensure that this whole thing is done only once because there will be a |
| // deluge of message in the traffic.log otherwise |
| |
| static pid_t check_prev_pid = watched_process_pid; |
| static pid_t check_current_pid = watched_process_pid; |
| if (check_prev_pid != watched_process_pid) { |
| check_prev_pid = watched_process_pid; |
| check_current_pid = watched_process_pid; |
| } |
| |
| if (check_prev_pid == check_current_pid) { |
| check_current_pid = -1; |
| int lerrno = errno; |
| mgmt_elog(stderr, "[LocalManager::sendMgmtMsgToProcesses] Error writing message\n"); |
| if (lerrno == ECONNRESET || lerrno == EPIPE) { // Connection closed by peer or Broken pipe |
| if ((kill(watched_process_pid, 0) < 0) && (errno == ESRCH)) { |
| // TS is down |
| pid_t tmp_pid = watched_process_pid; |
| ink_close_socket(watched_process_fd); |
| mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] " "Server Process has been terminated\n"); |
| if (lmgmt->run_proxy) { |
| mgmt_elog("[Alarms::signalAlarm] Server Process was reset\n"); |
| lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PROCESS_DIED); |
| } else { |
| mgmt_log("[TrafficManager] Server process shutdown\n"); |
| } |
| watched_process_fd = watched_process_pid = -1; |
| if (tmp_pid != -1) { /* Incremented after a pid: message is sent */ |
| proxy_running--; |
| } |
| proxy_started_at = -1; |
| REC_setInteger("proxy.node.proxy_running", 0); |
| // End of TS down |
| } else { |
| // TS is still up, but the connection is lost |
| char *err_msg = |
| "The TS-TM connection is broken for some reason. Either restart TS and TM or correct this error for TM to display TS statistics correctly"; |
| lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_SYSTEM_ERROR, err_msg); |
| } |
| |
| // check if the TS is down, by checking the pid |
| // if TS is down, then, |
| // raise an alarm |
| // set the variables so that TS is restarted later |
| // else (TS is still up) |
| // raise an alarm stating the problem |
| } |
| } |
| } |
| } |
| |
| } /* End LocalManager::sendMgmtMsgToProcesses */ |
| |
| |
| void |
| LocalManager::signalFileChange(char *var_name) |
| { |
| signalEvent(MGMT_EVENT_CONFIG_FILE_UPDATE, var_name); |
| return; |
| } /* End LocalManager::signalFileChange */ |
| |
| |
| void |
| LocalManager::signalEvent(int msg_id, const char *data_str) |
| { |
| signalEvent(msg_id, data_str, strlen(data_str) + 1); |
| return; |
| } /* End LocalManager::signalFileChange */ |
| |
| |
| void |
| LocalManager::signalEvent(int msg_id, const char *data_raw, int data_len) |
| { |
| MgmtMessageHdr *mh; |
| |
| mh = (MgmtMessageHdr *) xmalloc(sizeof(MgmtMessageHdr) + data_len); |
| mh->msg_id = msg_id; |
| mh->data_len = data_len; |
| memcpy((char *) mh + sizeof(MgmtMessageHdr), data_raw, data_len); |
| ink_assert(enqueue(mgmt_event_queue, mh)); |
| |
| return; |
| |
| } /* End LocalManager::signalEvent */ |
| |
| |
| /* |
| * processEventQueue() |
| * Function drains and processes the mgmt event queue |
| * notifying any registered callback functions and performing |
| * any mgmt tasks for each event. |
| */ |
| void |
| LocalManager::processEventQueue() |
| { |
| |
| bool handled_by_mgmt; |
| |
| while (!queue_is_empty(mgmt_event_queue)) { |
| |
| handled_by_mgmt = false; |
| |
| MgmtMessageHdr *mh = (MgmtMessageHdr *) dequeue(mgmt_event_queue); |
| char *data_raw = (char *) mh + sizeof(MgmtMessageHdr); |
| |
| // check if we have a local file update |
| if (mh->msg_id == MGMT_EVENT_CONFIG_FILE_UPDATE) { |
| |
| // records.config |
| if (!(strcmp(data_raw, "records.config"))) { |
| if (RecReadConfigFile() != REC_ERR_OKAY) { |
| mgmt_elog(stderr, "[fileUpdated] Config update failed for records.config\n"); |
| } |
| handled_by_mgmt = true; |
| } |
| // snmpd.config |
| if (!(strcmp(data_raw, "snmpd.cnf"))) { |
| #ifdef USE_SNMP |
| // need to restart SNMP agent |
| Debug("lm", "[TrafficManager] ==> flagging restart of Emanate agent\n"); |
| if (snmp) { |
| snmp->signalRereadConfig(); |
| } |
| #endif |
| handled_by_mgmt = true; |
| } |
| // admin_access.config |
| if (!(strcmp(data_raw, "admin_access.config"))) { |
| markAuthOtherUsersChange(); |
| handled_by_mgmt = true; |
| } |
| |
| } |
| |
| if (!handled_by_mgmt) { |
| if (processRunning() == false) { |
| // Fix INKqa04984 |
| // If traffic server hasn't completely come up yet, |
| // we will hold off until next round. |
| ink_assert(enqueue(mgmt_event_queue, mh)); |
| return; |
| } |
| Debug("lm", "[TrafficManager] ==> Sending signal event '%d'\n", mh->msg_id); |
| lmgmt->sendMgmtMsgToProcesses(mh); |
| } |
| |
| xfree(mh); |
| |
| } |
| |
| } /* End LocalManager::processEventQueue */ |
| |
| void |
| LocalManager::convert_filters() |
| { |
| // do filter_to_policy conversion before TS is launched |
| int status; |
| pid_t convert_pid; |
| bool found; |
| RecInt convert_on = REC_readInteger("proxy.config.auth.convert_filter_to_policy", &found); |
| ink_debug_assert(found); |
| |
| if (convert_on) { |
| RecString convert_bin = REC_readString("proxy.config.auth.convert_bin", &found); |
| ink_debug_assert(found); |
| |
| const size_t absolute_convert_binary_size = (sizeof(char) * (strlen(bin_path) + strlen(convert_bin)) + 2); |
| char *absolute_convert_binary = (char *) alloca(absolute_convert_binary_size); |
| snprintf(absolute_convert_binary, absolute_convert_binary_size, "%s%s%s", bin_path, DIR_SEP, convert_bin); |
| |
| // check that the binary exists |
| struct stat fileInfo; |
| if (stat(absolute_convert_binary, &fileInfo) < 0) { |
| mgmt_elog(stderr, |
| "[LocalManager::startProxy] " |
| "%s cannot be executed because it does not exist", absolute_convert_binary); |
| } else { |
| #ifdef POSIX_THREAD |
| if ((convert_pid = fork()) < 0) |
| #else |
| if ((convert_pid = fork1()) < 0) |
| #endif |
| { |
| mgmt_elog(stderr, "[LocalManager::startProxy] " "Unable to fork1 process for %s", absolute_convert_binary); |
| |
| } else if (convert_pid > 0) { /* Parent */ |
| bool script_done = false; |
| time_t timeout = 10; |
| time_t time_delta = 0; |
| time_t first_time = time(0); |
| |
| while (time_delta <= timeout) { |
| if (waitpid(convert_pid, &status, WNOHANG) != 0) { |
| Debug("lm-filter", "[LocalManager::startProxy] " "child pid %d has status", convert_pid); |
| script_done = true; |
| break; |
| } |
| time_delta = time(0) - first_time; |
| } |
| |
| // need to kill the child script process if it's not complete |
| if (!script_done) { |
| Debug("lm-filter", "[LocalManager::startProxy] " "kill filter_to_policy (child pid %d)", convert_pid); |
| mgmt_elog(stderr, "[LocalManager::startProxy] " |
| "%s failed to complete successfully.", absolute_convert_binary); |
| kill(convert_pid, SIGKILL); |
| waitpid(convert_pid, &status, 0); // to reap the thread |
| } else { |
| Debug("lm-filter", "[LocalManager::startProxy] " "%s execution completed\n", absolute_convert_binary); |
| } |
| } else { // invoke the converter script - no args |
| int res = execl(absolute_convert_binary, |
| convert_bin, NULL, NULL); |
| if (res < 0) { |
| mgmt_elog(stderr, "[LocalManager::startProxy] " |
| "%s failed to execute successfully.", absolute_convert_binary); |
| } |
| _exit(res); |
| } |
| if (convert_bin) |
| xfree(convert_bin); |
| } |
| } |
| } |
| |
| /* |
| * startProxy() |
| * Function fires up a proxy process. |
| */ |
| bool |
| LocalManager::startProxy() |
| { |
| |
| if (proxy_launch_outstanding) { |
| return false; |
| } |
| mgmt_log(stderr, "[LocalManager::startProxy] Launching ts process\n"); |
| |
| convert_filters(); |
| |
| // INKqa10742 |
| plugin_list.clear(); |
| |
| pid_t pid; |
| |
| // Before we do anything lets check for the existence of |
| // the traffic server binary along with it's execute permmissions |
| if (access(absolute_proxy_binary, F_OK) < 0) { |
| // Error can't find trafic_server |
| mgmt_elog(stderr, "[LocalManager::startProxy] Unable to find traffic server at %s\n", absolute_proxy_binary); |
| return false; |
| } |
| // traffic server binary exists, check permissions |
| else if (access(absolute_proxy_binary, R_OK | X_OK) < 0) { |
| // Error don't have proper permissions |
| mgmt_elog(stderr, "[LocalManager::startProxy] Unable to access %s due to bad permisssions \n", |
| absolute_proxy_binary); |
| return false; |
| } |
| |
| if (env_prep) { |
| #ifdef POSIX_THREAD |
| if ((pid = fork()) < 0) |
| #else |
| if ((pid = fork1()) < 0) |
| #endif |
| { |
| mgmt_elog(stderr, "[LocalManager::startProxy] Unable to fork1 prep process\n"); |
| return false; |
| } else if (pid > 0) { |
| int estatus; |
| waitpid(pid, &estatus, 0); |
| } else { |
| int res; |
| char env_prep_bin[1024]; |
| |
| snprintf(env_prep_bin, sizeof(env_prep_bin), "%s/%s", bin_path, env_prep); |
| res = execl(env_prep_bin, env_prep, NULL); |
| _exit(res); |
| } |
| } |
| #ifdef POSIX_THREAD |
| if ((pid = fork()) < 0) |
| #else |
| if ((pid = fork1()) < 0) |
| #endif |
| { |
| mgmt_elog(stderr, "[LocalManager::startProxy] Unable to fork1 process\n"); |
| return false; |
| } else if (pid > 0) { /* Parent */ |
| proxy_launch_pid = pid; |
| proxy_launch_outstanding = true; |
| proxy_started_at = time(NULL); |
| ++proxy_launch_count; |
| REC_setInteger("proxy.node.restarts.proxy.start_time", proxy_started_at); |
| REC_setInteger("proxy.node.restarts.proxy.restart_count", proxy_launch_count); |
| } else { |
| int res, i = 0, n; |
| char real_proxy_options[2048], *options[32], *last, *tok; |
| |
| snprintf(real_proxy_options, sizeof(real_proxy_options), "%s", proxy_options); |
| n = strlen(real_proxy_options); |
| |
| // Check if we need to pass down port/fd information to |
| // traffic_server |
| if (proxy_server_fd[0] != -1) { |
| snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, " -A"); |
| n = strlen(real_proxy_options); |
| // Handle some syntax issues |
| if (proxy_server_fd[0] != -1) { |
| snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, ","); |
| n = strlen(real_proxy_options); |
| } |
| // Fill in the rest of the fd's |
| if (proxy_server_fd[0] != -1) { |
| snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, |
| "%d:%s", proxy_server_fd[0], proxy_server_port_attributes[0]); |
| n = strlen(real_proxy_options); |
| for (i = 1; i<MAX_PROXY_SERVER_PORTS && proxy_server_fd[i]> 0; i++) { |
| snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, |
| ",%d:%s", proxy_server_fd[i], proxy_server_port_attributes[i]); |
| n = strlen(real_proxy_options); |
| } |
| } |
| } |
| |
| Debug("lm", "[LocalManager::startProxy] Launching %s with options '%s'\n", |
| absolute_proxy_binary, real_proxy_options); |
| |
| for (i = 0; i < 32; i++) |
| options[i] = NULL; |
| options[0] = absolute_proxy_binary; |
| i = 1; |
| tok = ink_strtok_r(real_proxy_options, " ", &last); |
| options[i++] = tok; |
| while (i < 32 && (tok = ink_strtok_r(NULL, " ", &last))) { |
| options[i++] = tok; |
| } |
| |
| if (!strstr(proxy_options, "-M")) { // Make sure we're starting the proxy in mgmt mode |
| mgmt_fatal(stderr, "[LocalManager::startProxy] ts options must contain -M"); |
| } |
| |
| res = execv(absolute_proxy_binary, options); |
| mgmt_elog(stderr, "[LocalManager::startProxy] Exec of %s failed\n", absolute_proxy_binary); |
| _exit(res); |
| } |
| return true; |
| |
| } /* End LocalManager::startProxy */ |
| |
| |
| /* |
| * listenForProxy() |
| * Function listens on the accept port of the proxy, so users aren't dropped. |
| */ |
| void |
| LocalManager::listenForProxy() |
| { |
| if (!run_proxy) |
| return; |
| |
| // We we are not already bound, bind the port |
| for (int i = 0; i < MAX_PROXY_SERVER_PORTS; i++) { |
| if (proxy_server_port[i] != -1) { |
| |
| if (proxy_server_fd[i] < 0) { |
| switch (*proxy_server_port_attributes[i]) { |
| case 'D': |
| // D is for DNS proxy, udp only |
| proxy_server_fd[i] = bindProxyPort(proxy_server_port[i], proxy_server_incoming_ip_to_bind, SOCK_DGRAM); |
| break; |
| default: |
| proxy_server_fd[i] = bindProxyPort(proxy_server_port[i], proxy_server_incoming_ip_to_bind, SOCK_STREAM); |
| } |
| } |
| |
| if (*proxy_server_port_attributes[i] != 'D') { |
| if ((listen(proxy_server_fd[i], 1024)) < 0) { |
| mgmt_fatal(stderr, "[LocalManager::listenForProxy] Unable to listen on socket: %d\n", proxy_server_port[i]); |
| } |
| mgmt_log(stderr, "[LocalManager::listenForProxy] Listening on port: %d\n", proxy_server_port[i]); |
| } else { |
| break; |
| } |
| } |
| } |
| return; |
| } /* End LocalManager::listenForProxy */ |
| |
| // bool removeRootPriv() |
| // |
| // - Returns true on success |
| // and false on failure |
| // - no-op on WIN32 |
| bool |
| removeRootPriv(uid_t euid) |
| { |
| if (seteuid(euid) < 0) { |
| Debug("lm", "[restoreRootPriv] seteuid failed : %s\n", strerror(errno)); |
| return false; |
| } |
| |
| Debug("lm", "[removeRootPriv] removed root privileges. Euid is %d\n", euid); |
| |
| return true; |
| } |
| |
| |
| // bool restoreRootPriv() |
| // |
| // - Returns true on success |
| // and false on failure |
| // - no-op on WIN32 |
| bool |
| restoreRootPriv(uid_t *old_euid) |
| { |
| if (old_euid) |
| *old_euid = geteuid(); |
| if (seteuid(0) < 0) { |
| Debug("lm", "[restoreRootPriv] seteuid root failed : %s\n", strerror(errno)); |
| return false; |
| } |
| |
| Debug("lm", "[restoreRootPriv] restored root privileges. Euid is %d\n", 0); |
| |
| return true; |
| } |
| |
| /* |
| * bindProxyPort() |
| * Function binds the accept port of the proxy |
| * Also, type specifies udp or tcp |
| */ |
| int |
| bindProxyPort(int proxy_port, in_addr_t incoming_ip_to_bind, int type) |
| { |
| int one = 1; |
| struct sockaddr_in proxy_addr; |
| int proxy_port_fd = -1; |
| bool privBoost = false; |
| uid_t euid = geteuid(); |
| uid_t saved_euid = 0; |
| |
| if (proxy_port < 1024 && euid != 0) { |
| if (restoreRootPriv(&saved_euid) == false) { |
| mgmt_elog(stderr, "[bindProxyPort] Unable to get root priviledges to bind port %d. euid is %d. Exiting\n", |
| proxy_port, euid); |
| _exit(0); |
| } else { |
| privBoost = true; |
| } |
| } |
| |
| /* Setup reliable connection, for large config changes */ |
| if ((proxy_port_fd = socket(AF_INET, type, 0)) < 0) { |
| mgmt_elog(stderr, "[bindProxyPort] Unable to create socket : %s\n", strerror(errno)); |
| _exit(1); |
| } |
| if (setsockopt(proxy_port_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) { |
| mgmt_elog(stderr, "[bindProxyPort] Unable to set socket options: %d : %s\n", proxy_port, strerror(errno)); |
| _exit(1); |
| } |
| |
| memset(&proxy_addr, 0, sizeof(proxy_addr)); |
| proxy_addr.sin_family = AF_INET; |
| proxy_addr.sin_addr.s_addr = incoming_ip_to_bind; |
| proxy_addr.sin_port = htons(proxy_port); |
| |
| if ((bind(proxy_port_fd, (struct sockaddr *) &proxy_addr, sizeof(proxy_addr))) < 0) { |
| mgmt_elog(stderr, "[bindProxyPort] Unable to bind socket: %d : %s\n", proxy_port, strerror(errno)); |
| _exit(1); |
| } |
| |
| Debug("lm", "[bindProxyPort] Successfully bound proxy port %d\n", proxy_port); |
| |
| if (privBoost == true) { |
| if (removeRootPriv(saved_euid) == false) { |
| mgmt_elog(stderr, "[bindProxyPort] Unable to reset permissions to euid %d. Exiting...\n", getuid()); |
| _exit(1); |
| } |
| } |
| return proxy_port_fd; |
| |
| } /* End bindProxyPort */ |
| |
| void |
| LocalManager::signalAlarm(int alarm_id, char *desc, char *ip) |
| { |
| if (alarm_keeper) |
| alarm_keeper->signalAlarm((alarm_t) alarm_id, desc, ip); |
| } /* signalAlarm */ |