package com.sun.slp;
import java.io.*;
import java.net.*;
import java.util.*;
class RequestHandler extends Thread {
private SLPConfig config;
private ServerDATable daTable;
private InetAddress interfac = null;
private Socket sock = null;
private DatagramPacket packet = null;
private InetAddress clientAddr = null;
private int port = 0;
private ServiceTable serviceTable = null;
private SrvLocMsg toForward = null;
private InputStream inStream = null;
private OutputStream outStream = null;
static private Hashtable inProgress = new Hashtable();
protected void finalize() throws IOException {
if (sock != null) sock.close();
}
RequestHandler(InputStream in, OutputStream out, SLPConfig config_in) {
config = config_in;
sock = null;
inStream = in;
outStream = out;
clientAddr = config.getLoopback();
port = 427;
interfac = clientAddr;
try {
serviceTable = ServiceTable.getServiceTable();
} catch (ServiceLocationException ex) {
}
}
RequestHandler(Socket sock_in, InetAddress interfac, SLPConfig config_in) {
Assert.slpassert((sock_in != null),
"rh_null_sock",
new Object[0]);
Assert.slpassert((config_in != null),
"ls_null_config",
new Object[0]);
config = config_in;
sock = sock_in;
clientAddr = sock.getInetAddress();
port = sock.getPort();
this.interfac = interfac;
try {
serviceTable = ServiceTable.getServiceTable();
} catch (ServiceLocationException ex) {
}
}
RequestHandler(DatagramPacket packet_in,
InetAddress interfac,
SLPConfig config_in) {
Assert.slpassert((packet_in != null),
"rh_null_packy",
new Object[0]);
Assert.slpassert((config_in != null),
"ls_null_config",
new Object[0]);
config = config_in;
packet = packet_in;
clientAddr = packet.getAddress();
port = packet.getPort();
this.interfac = interfac;
try {
serviceTable = ServiceTable.getServiceTable();
daTable = ServerDATable.getServerDATable();
} catch (ServiceLocationException ex) {
}
}
static String stringifyBuffer(byte[] bytes) {
StringBuffer buf = new StringBuffer();
int i, n = bytes.length;
for (i = 0; i < n; i++) {
byte b = bytes[i];
if ((b >= 0x21) && (b < 0x7e)) {
buf.append((char)b);
} else {
buf.append("\\"+Integer.toHexString(((int)b) & 0xFF));
}
}
return buf.toString();
}
public void run() {
if (sock != null || inStream != null) {
setName("Stream Request Handler "+clientAddr+":"+port);
if (sock != null) {
try {
sock.setSoTimeout(0);
} catch (SocketException ex) {
}
}
try {
daTable = ServerDATable.getServerDATable();
} catch (ServiceLocationException e) {
}
handleStream();
if (sock != null) {
try {
sock.close();
sock = null;
} catch (IOException ex) {
}
}
} else {
setName("Datagram Request Handler "+clientAddr+":"+port);
byte[] inbuf = packet.getData();
byte[] xidBuf = new byte[2];
System.arraycopy(inbuf, SrvLocHeader.XID_OFFSET, xidBuf, 0, 2);
int xid = 0;
xid = (int)((char)xidBuf[0] & 0xFF) << 8;
xid += (int)((char)xidBuf[1] & 0xFF);
String syncTableKey =
(Integer.valueOf(xid)).toString() +
clientAddr.getHostAddress();
boolean there = false;
synchronized (inProgress) {
there = (inProgress.get(syncTableKey) != null);
if (!there) {
inProgress.put(syncTableKey, this);
}
}
if (there) {
if (config.traceDrop()) {
config.writeLog("rh_rqst_in_progress",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac});
}
return;
}
DataInputStream dis =
new DataInputStream(new ByteArrayInputStream(inbuf));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
handleRequest(dis, baos, false);
byte[] outbuf = baos.toByteArray();
if (outbuf != null && outbuf.length > 0) {
sendDatagramReply(outbuf);
}
} catch (IOException ex) {
if (config.traceDrop()) {
config.writeLog("rh_datagram_ioe",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac,
ex.getMessage()});
}
}
synchronized (inProgress) {
RequestHandler rh =
(RequestHandler)inProgress.get(syncTableKey);
if (rh == this) {
inProgress.remove(syncTableKey);
}
}
}
}
private void handleStream() {
try {
DataInputStream dis = null;
DataOutputStream dos = null;
if (inStream != null) {
dis = new DataInputStream(inStream);
dos = new DataOutputStream(outStream);
} else {
dis = new DataInputStream(sock.getInputStream());
dos = new DataOutputStream(sock.getOutputStream());
}
do {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
boolean parseError = handleRequest(dis, baos, true);
dos.write(baos.toByteArray(), 0, baos.size());
if (toForward != null) {
try {
daTable.forwardSAMessage(toForward, clientAddr);
toForward = null;
} catch (ServiceLocationException ex) {
config.writeLog("sa_forwarding_exception",
new Object[] {
Short.valueOf(ex.getErrorCode()),
Integer.toHexString(toForward.getHeader().xid),
ex.getMessage()});
}
}
if (parseError && config.traceMsg()) {
config.writeLog("rh_tcp_error",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac});
break;
}
} while (true);
} catch (EOFException ex) {
if (config.traceMsg()) {
config.writeLog("rh_socket_closed",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac});
}
} catch (IOException ex) {
if (config.traceDrop()) {
config.writeLog("ioexception_server_stream",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac,
ex.getMessage()});
}
}
}
private void sendDatagramReply(byte[] outbuf) {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
DatagramPacket dpOut =
new DatagramPacket(outbuf, outbuf.length, clientAddr, port);
ds.send(dpOut);
if (toForward != null) {
try {
daTable.forwardSAMessage(toForward, clientAddr);
toForward = null;
} catch (ServiceLocationException ex) {
config.writeLog("sle_forward_error",
new Object[] {
Integer.valueOf(ex.getErrorCode()),
Integer.toHexString(toForward.getHeader().xid),
ex.getMessage()});
}
}
} catch (SocketException ex) {
if (config.traceDrop()) {
config.writeLog("rh_socket_error",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac,
ex.getMessage()});
}
} catch (IOException ex) {
if (config.traceDrop()) {
config.writeLog(
"rh_ioexception_reply",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac,
ex.getMessage()});
}
} finally {
if (ds != null) {
ds.close();
}
}
}
private boolean
handleRequest(DataInputStream dis,
ByteArrayOutputStream baos,
boolean isTCP)
throws IOException {
boolean parseError = false;
SrvLocMsg msg = internalize(dis, isTCP);
SrvLocMsg rply = msg;
if (msg != null) {
SrvLocHeader hdr = msg.getHeader();
if (hdr.errCode == ServiceLocationException.OK) {
if (config.traceMsg()) {
config.writeLog("rh_rqst_in",
new Object[] {Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac,
msg.getHeader()});
}
rply = dispatch(msg);
if (rply == null) {
if (config.traceMsg()) {
config.writeLog("rh_rply_null",
new Object[] {
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return parseError;
}
} else {
if (msg.getHeader().mcast) {
rply = null;
if (config.traceDrop()) {
config.writeLog("rh_multi_error",
new Object[] {
msg.getClass().getName(),
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
} else if (isTCP) {
parseError = true;
}
}
}
if (rply != null) {
SrvLocHeader hdr = rply.getHeader();
ServiceLocationException ex = null;
try {
hdr.externalize(baos, false, isTCP);
} catch (ServiceLocationException sle) {
ex = sle;
}
if (config.traceMsg()) {
config.writeLog("rh_rply_out",
new Object[] {Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac,
rply.getHeader()});
}
if (ex != null) {
baos.reset();
rply = hdr.makeErrorReply(ex);
Assert.slpassert(msg != null,
"rh_header_class_error",
new Object[] {ex.getMessage()});
hdr = rply.getHeader();
try {
hdr.externalize(baos, false, isTCP);
} catch (ServiceLocationException exx) {
}
}
} else if (config.traceMsg()) {
String xidStr = "<null message>";
if (msg != null) {
SrvLocHeader hdr = msg.getHeader();
xidStr = Integer.toHexString(hdr.xid);
}
config.writeLog("rh_rply_null",
new Object[] {xidStr,
clientAddr,
Integer.valueOf(port),
interfac});
}
return parseError;
}
private SrvLocMsg
internalize(DataInputStream dis, boolean viaTCP) throws IOException {
int ver = 0, fun = 0;
Assert.slpassert((dis != null),
"rh_null_bais",
new Object[0]);
try {
byte[] b = new byte[2];
dis.readFully(b, 0, 2);
ver = (int) ((char)b[0] & 0XFF);
fun = (int) ((char)b[1] & 0XFF);
} catch (IOException ex) {
if (!(ex instanceof EOFException)) {
printInternalizeErrorMessage(ver, fun, ex);
}
throw ex;
}
SrvLocMsg msg = null;
SrvLocHeader hdr = null;
try {
hdr = SrvLocHeader.newInstance(ver);
if (hdr == null) {
if (ver > Defaults.version ||
(config.isV1Supported() && config.isDA())) {
throw
new ServiceLocationException(
ServiceLocationException.VERSION_NOT_SUPPORTED,
"rh_version_number_error",
new Object[] {Integer.valueOf(ver),
clientAddr,
Integer.valueOf(port),
interfac});
} else {
return null;
}
}
if (viaTCP) {
hdr.setPacketLength(Integer.MAX_VALUE);
}
hdr.parseHeader(fun, dis);
if ((msg = hdr.parseMsg(dis)) != null) {
hdr.parseOptions(dis);
}
} catch (Exception ex) {
printInternalizeErrorMessage(ver, fun, ex);
msg = null;
if (fun != SrvLocHeader.DAAdvert &&
fun != SrvLocHeader.SAAdvert &&
hdr != null) {
msg = hdr.makeErrorReply(ex);
}
}
return msg;
}
private void printInternalizeErrorMessage(int ver, int fun, Exception ex) {
if (config.traceDrop()) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
short errCode = ServiceLocationException.INTERNAL_SYSTEM_ERROR;
if (ex instanceof ServiceLocationException) {
errCode = ((ServiceLocationException)ex).getErrorCode();
} else if (ex instanceof IllegalArgumentException) {
errCode = ServiceLocationException.PARSE_ERROR;
}
String exMsg = "(" + errCode + "):" + ex.getMessage();
config.writeLog("rh_unparse_exception",
new Object[] {clientAddr,
Integer.valueOf(port),
interfac,
Integer.valueOf(ver),
Integer.valueOf(fun),
exMsg,
sw.toString()});
}
}
SrvLocMsg dispatch(SrvLocMsg rqst) {
SrvLocHeader hdr = rqst.getHeader();
boolean mcast = hdr.mcast;
if (rqst instanceof CDAAdvert) {
CDAAdvert msg = (CDAAdvert)rqst;
msg.setIsUnsolicited(true);
if (!config.passiveDADetection() &&
msg.isUnsolicited() &&
!msg.isGoingDown()) {
if (config.traceDrop()) {
config.writeLog("rh_passive_drop",
new Object[] {msg.URL,
hdr.scopes});
}
} else if (msg.isGoingDown() && msg.isUnsolicited() &&
isLocalHostURL(msg.URL) && config.isDA()) {
Vector scopes = (Vector)hdr.scopes.clone();
DATable.filterScopes(scopes,
config.getSAConfiguredScopes(), true);
if (scopes.size() > 0) {
daTable.handleAdvertIn(msg);
} else {
Vector discoveredScopes = new Vector();
try {
discoveredScopes = daTable.findScopes();
} catch (ServiceLocationException ex) {
}
Vector serverScopes = config.getSAConfiguredScopes();
Vector interfaces = config.getInterfaces();
Vector daAttributes = config.getDAAttributes();
if (config.traceAll() ||
config.traceMsg() ||
config.traceDrop() ||
config.traceDATraffic()) {
config.writeLog("goodby_da",
new Object[] {interfaces,
serverScopes,
discoveredScopes,
daAttributes});
}
System.exit(0);
}
} else {
daTable.handleAdvertIn(msg);
}
return null;
} else if (rqst instanceof CSAAdvert) {
CSAAdvert msg = (CSAAdvert)rqst;
if ((hdr.xid == 0) && isLocalHostURL(msg.URL) && !config.isDA()) {
Vector scopes = (Vector)hdr.scopes.clone();
DATable.filterScopes(scopes,
config.getSAConfiguredScopes(), true);
if (scopes.size() <= 0) {
Vector discoveredScopes = new Vector();
try {
discoveredScopes = daTable.findScopes();
} catch (ServiceLocationException ex) {
}
Vector serverScopes = config.getSAConfiguredScopes();
Vector interfaces = config.getInterfaces();
Vector saAttributes = config.getSAAttributes();
if (config.traceAll() ||
config.traceMsg() ||
config.traceDrop() ||
config.traceDATraffic()) {
config.writeLog("goodby",
new Object[] {interfaces,
serverScopes,
discoveredScopes,
saAttributes});
}
System.exit(0);
}
}
if (config.traceDrop()) {
config.writeLog("rh_client_sa_advert_drop",
new Object[] {Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
if (rqst instanceof SSrvReg) {
return dispatchReg((SSrvReg)rqst,
serviceTable);
} else if (rqst instanceof SSrvDereg) {
return dispatchDereg((SSrvDereg)rqst,
serviceTable);
}
if (isPreviousResponder(hdr)) {
if (config.traceDrop()) {
config.writeLog("rh_prev_resp",
new Object[] {Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
if (rqst instanceof SSrvTypeMsg) {
return dispatchSrvType((SSrvTypeMsg)rqst,
serviceTable);
} else if (rqst instanceof SAttrMsg) {
return dispatchAttr((SAttrMsg)rqst,
serviceTable);
} else if (rqst instanceof SSrvMsg) {
return dispatchSrv((SSrvMsg)rqst,
serviceTable);
} else {
Assert.slpassert(false,
"rh_rqst_type_err",
new Object[] {rqst});
}
return null;
}
private SrvLocMsg dispatchReg(SSrvReg rqst,
ServiceTable serviceTable) {
SrvLocHeader hdr = rqst.getHeader();
if (hdr.mcast && config.traceDrop()) {
if (config.traceDrop()) {
config.writeLog("rh_no_multi",
new Object[] {"SrvReg",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
SrvLocMsg rply = serviceTable.register(rqst);
if (rply != null) {
hdr = rply.getHeader();
if (hdr.errCode == ServiceLocationException.OK) {
toForward = rqst;
}
}
return rply;
}
private SrvLocMsg dispatchDereg(SSrvDereg rqst,
ServiceTable serviceTable) {
SrvLocHeader hdr = rqst.getHeader();
if (hdr.mcast && config.traceDrop()) {
if (config.traceDrop()) {
config.writeLog("rh_no_multi",
new Object[] {"SrvDereg",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
SrvLocMsg rply = serviceTable.deregister(rqst);
if (rply != null) {
hdr = rply.getHeader();
if (hdr.errCode == ServiceLocationException.OK) {
toForward = rqst;
}
}
return rply;
}
private SrvLocMsg dispatchSrvType(SSrvTypeMsg rqst,
ServiceTable serviceTable) {
SrvLocHeader hdr = rqst.getHeader();
boolean mcast = hdr.mcast;
if (mcast && config.isDA()) {
if (config.traceDrop()) {
config.writeLog("rh_drop_da_multi",
new Object[] {"SrvTypeRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
SrvLocMsg rply = serviceTable.findServiceTypes(rqst);
hdr = rply.getHeader();
if (mcast &&
((hdr.errCode != ServiceLocationException.OK) ||
(hdr.getNumReplies() == 0))) {
if (config.traceDrop()) {
config.writeLog("rh_multi_error",
new Object[] {"SrvTypeRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
return rply;
}
private SrvLocMsg dispatchAttr(SAttrMsg rqst,
ServiceTable serviceTable) {
SrvLocHeader hdr = rqst.getHeader();
boolean mcast = hdr.mcast;
if (mcast && config.isDA()) {
if (config.traceDrop()) {
config.writeLog("rh_drop_da_multi",
new Object[] {"AttrRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
SrvLocMsg rply = serviceTable.findAttributes(rqst);
hdr = rply.getHeader();
if (mcast &&
((hdr.errCode != ServiceLocationException.OK) ||
(hdr.getNumReplies() == 0))) {
if (config.traceDrop()) {
config.writeLog("rh_multi_error",
new Object[] {"AttrRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
return rply;
}
private SrvLocMsg dispatchSrv(SSrvMsg rqst,
ServiceTable serviceTable) {
SrvLocHeader hdr = rqst.getHeader();
boolean mcast = hdr.mcast;
String serviceType = rqst.serviceType;
SrvLocMsg rply = null;
if (serviceType.equals(Defaults.DA_SERVICE_TYPE.toString())) {
if (config.isDA()) {
rply = serviceTable.makeDAAdvert(rqst,
interfac,
config);
hdr = rply.getHeader();
if ((hdr.errCode != ServiceLocationException.OK) &&
config.traceMsg()) {
config.writeLog("rh_advert_error",
new Object[] { Integer.valueOf(hdr.errCode),
"DAAdvert",
""});
}
}
if (hdr.errCode != ServiceLocationException.OK &&
mcast) {
if (config.traceDrop()) {
config.writeLog("rh_drop_srv",
new Object[] {
"DA SrvRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
return rply;
} else if (serviceType.equals(Defaults.SA_SERVICE_TYPE.toString())) {
if (!mcast) {
if (config.traceDrop()) {
config.writeLog("rh_no_srv_uni",
new Object[] {
"SA SrvRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
try {
rply = serviceTable.makeSAAdvert(rqst,
interfac,
config);
} catch (ServiceLocationException ex) {
config.writeLog("rh_advert_error",
new Object [] {Integer.valueOf(ex.getErrorCode()),
"SAAdvert",
ex.getMessage()});
}
if (rply == null && config.traceDrop()) {
config.writeLog("rh_drop_srv",
new Object[] {"SA SrvRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return rply;
}
if (mcast && config.isDA()) {
if (config.traceDrop()) {
config.writeLog("rh_drop_da_multi",
new Object[] {"SrvRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
SrvLocMsg smrply = serviceTable.findServices(rqst);
hdr = smrply.getHeader();
if (mcast &&
((hdr.errCode != ServiceLocationException.OK) ||
(hdr.getNumReplies() == 0))) {
if (config.traceDrop()) {
config.writeLog("rh_multi_error",
new Object[] {"SrvRqst",
Integer.toHexString(hdr.xid),
clientAddr,
Integer.valueOf(port),
interfac});
}
return null;
}
return smrply;
}
boolean isLocalHostURL(ServiceURL url) {
String hostAddr = url.getHost();
Vector interfaces = config.getInterfaces();
InetAddress addr = null;
try {
addr = InetAddress.getByName(hostAddr);
} catch (UnknownHostException ex) {
return false;
}
if (interfaces.contains(addr)) {
return true;
}
return false;
}
public boolean isPreviousResponder(SrvLocHeader hdr) {
if ((hdr.previousResponders == null) ||
(hdr.mcast == false)) {
return false;
}
Vector previousResponders = hdr.previousResponders;
Enumeration e = null;
Vector interfaces = config.getInterfaces();
for (e = previousResponders.elements(); e.hasMoreElements(); ) {
try {
String sHost = ((String)e.nextElement());
InetAddress iaHost = InetAddress.getByName(sHost);
if (interfaces.contains(iaHost)) {
return true;
}
} catch (UnknownHostException ex) {
}
}
return false;
}
static {
SrvLocHeader.addHeaderClass(Defaults.DEFAULT_SERVER_HEADER_CLASS,
Defaults.version);
}
}