209 lines
7.6 KiB
Java
209 lines
7.6 KiB
Java
/*
|
|
* 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.
|
|
*/
|
|
|
|
|
|
package org.apache.catalina.ha.backend;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.BufferedWriter;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.io.OutputStreamWriter;
|
|
import java.net.InetAddress;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.Socket;
|
|
import java.util.StringTokenizer;
|
|
|
|
import org.apache.juli.logging.Log;
|
|
import org.apache.juli.logging.LogFactory;
|
|
|
|
/*
|
|
* Sender to proxies using multicast socket.
|
|
*/
|
|
public class TcpSender
|
|
implements Sender {
|
|
|
|
private static final Log log = LogFactory.getLog(HeartbeatListener.class);
|
|
|
|
HeartbeatListener config = null;
|
|
|
|
/**
|
|
* Proxies.
|
|
*/
|
|
protected Proxy[] proxies = null;
|
|
|
|
|
|
/**
|
|
* Active connections.
|
|
*/
|
|
|
|
protected Socket[] connections = null;
|
|
protected BufferedReader[] connectionReaders = null;
|
|
protected BufferedWriter[] connectionWriters = null;
|
|
|
|
|
|
@Override
|
|
public void init(HeartbeatListener config) throws Exception {
|
|
this.config = config;
|
|
StringTokenizer tok = new StringTokenizer(config.getProxyList(), ",");
|
|
proxies = new Proxy[tok.countTokens()];
|
|
int i = 0;
|
|
while (tok.hasMoreTokens()) {
|
|
String token = tok.nextToken().trim();
|
|
int pos = token.indexOf(':');
|
|
if (pos <=0)
|
|
throw new Exception("bad ProxyList");
|
|
proxies[i] = new Proxy();
|
|
proxies[i].port = Integer.parseInt(token.substring(pos + 1));
|
|
try {
|
|
proxies[i].address = InetAddress.getByName(token.substring(0, pos));
|
|
} catch (Exception e) {
|
|
throw new Exception("bad ProxyList");
|
|
}
|
|
i++;
|
|
}
|
|
connections = new Socket[proxies.length];
|
|
connectionReaders = new BufferedReader[proxies.length];
|
|
connectionWriters = new BufferedWriter[proxies.length];
|
|
|
|
}
|
|
|
|
@Override
|
|
public int send(String mess) throws Exception {
|
|
if (connections == null) {
|
|
log.error("Not initialized");
|
|
return -1;
|
|
}
|
|
String requestLine = "POST " + config.getProxyURL() + " HTTP/1.0";
|
|
|
|
for (int i = 0; i < connections.length; i++) {
|
|
if (connections[i] == null) {
|
|
try {
|
|
if (config.getHost() != null) {
|
|
connections[i] = new Socket();
|
|
InetAddress addr = InetAddress.getByName(config.getHost());
|
|
InetSocketAddress addrs = new InetSocketAddress(addr, 0);
|
|
connections[i].setReuseAddress(true);
|
|
connections[i].bind(addrs);
|
|
addrs = new InetSocketAddress(proxies[i].address, proxies[i].port);
|
|
connections[i].connect(addrs);
|
|
} else
|
|
connections[i] = new Socket(proxies[i].address, proxies[i].port);
|
|
connectionReaders[i] = new BufferedReader(new InputStreamReader(connections[i].getInputStream()));
|
|
connectionWriters[i] = new BufferedWriter(new OutputStreamWriter(connections[i].getOutputStream()));
|
|
} catch (Exception ex) {
|
|
log.error("Unable to connect to proxy: " + ex);
|
|
close(i);
|
|
}
|
|
}
|
|
if (connections[i] == null)
|
|
continue; // try next proxy in the list
|
|
BufferedWriter writer = connectionWriters[i];
|
|
try {
|
|
writer.write(requestLine);
|
|
writer.write("\r\n");
|
|
writer.write("Content-Length: " + mess.length() + "\r\n");
|
|
writer.write("User-Agent: HeartbeatListener/1.0\r\n");
|
|
writer.write("Connection: Keep-Alive\r\n");
|
|
writer.write("\r\n");
|
|
writer.write(mess);
|
|
writer.write("\r\n");
|
|
writer.flush();
|
|
} catch (Exception ex) {
|
|
log.error("Unable to send collected load information to proxy: " + ex);
|
|
close(i);
|
|
}
|
|
if (connections[i] == null)
|
|
continue; // try next proxy in the list
|
|
|
|
/* Read httpd answer */
|
|
String responseStatus = connectionReaders[i].readLine();
|
|
if (responseStatus == null) {
|
|
log.error("Unable to read response from proxy");
|
|
close(i);
|
|
continue;
|
|
} else {
|
|
responseStatus = responseStatus.substring(responseStatus.indexOf(' ') + 1, responseStatus.indexOf(' ', responseStatus.indexOf(' ') + 1));
|
|
int status = Integer.parseInt(responseStatus);
|
|
if (status != 200) {
|
|
log.error("Status is " + status);
|
|
close(i);
|
|
continue;
|
|
}
|
|
|
|
// read all the headers.
|
|
String header = connectionReaders[i].readLine();
|
|
int contentLength = 0;
|
|
while (!"".equals(header)) {
|
|
int colon = header.indexOf(':');
|
|
String headerName = header.substring(0, colon).trim();
|
|
String headerValue = header.substring(colon + 1).trim();
|
|
if ("content-length".equalsIgnoreCase(headerName)) {
|
|
contentLength = Integer.parseInt(headerValue);
|
|
}
|
|
header = connectionReaders[i].readLine();
|
|
}
|
|
if (contentLength > 0) {
|
|
char[] buf = new char[512];
|
|
while (contentLength > 0) {
|
|
int thisTime = (contentLength > buf.length) ? buf.length : contentLength;
|
|
int n = connectionReaders[i].read(buf, 0, thisTime);
|
|
if (n <= 0) {
|
|
log.error("Read content failed");
|
|
close(i);
|
|
break;
|
|
} else {
|
|
contentLength -= n;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Close connection.
|
|
* @param i The index of the connection that will be closed
|
|
*/
|
|
protected void close(int i) {
|
|
try {
|
|
if (connectionReaders[i] != null) {
|
|
connectionReaders[i].close();
|
|
}
|
|
} catch (IOException e) {
|
|
}
|
|
connectionReaders[i] = null;
|
|
try {
|
|
if (connectionWriters[i] != null) {
|
|
connectionWriters[i].close();
|
|
}
|
|
} catch (IOException e) {
|
|
}
|
|
connectionWriters[i] = null;
|
|
try {
|
|
if (connections[i] != null) {
|
|
connections[i].close();
|
|
}
|
|
} catch (IOException e) {
|
|
}
|
|
connections[i] = null;
|
|
}
|
|
}
|