/**
* Compose various SLPv2 messages (protocol stack)
* Return the message in a byte array
*
*/
package eu.artemis.shield.discovery.slpdaemon.impl;
import java.io.*;
import java.util.*;
public class slpMsgComposer {
DataOutputStream d;
ByteArrayOutputStream b;
slpMsgComposer() {
b = new ByteArrayOutputStream();
d = new DataOutputStream(b);
}
/**
* Compose SLP common message header, flags may be set, there
* may exist extensions, language tag is NOT included here
*+--------------+-----------------+----------------------------------+
*| Version | Function-ID | Length |
*+--------------+-+-+-+-----------+---------------+------------------+
*| Length cont. |O|F|R| Reserved | Next Ext. Offset |
*+--------------+-+-+-+-----------+---------------+------------------+
*| Next Ext. Offset Cont. | XID |
*+--------------------------------+----------------------------------+
*/
private void Header(int type, int len, int flag, int xid) {
try {
b.reset();
d.writeByte(Const.version); // SLP version
d.writeByte(type); // Function type
d.writeByte(0); // len
d.writeShort(len); // length
d.writeShort(flag); // flag bits
d.writeByte(0); // next ext. offset
d.writeShort(0); // next ext. offset
d.writeShort(xid); // XID
} catch (Exception e) {
da.append(e);
}
}
/**
* Put a string in the byte[], precede with its length.
* The string could be empty, with a length of 0.
* If the string is null, then no action is taken.
*/
private void putString(String s) {
if (s == null) return;
try {
d.writeShort(s.length());
if (s.length() > 0) {
d.writeBytes(s);
}
} catch (Exception e) {
da.append(e);
}
}
/**
* put an integer as a byte (normally zero) in the byte[]
*/
private void putByte(int z) {
try {
d.writeByte(z);
} catch (Exception e) {
da.append(e.toString());
}
}
/**
* put an integer as a short (normally as error code) in the byte[]
*/
private void putShort(int z) {
try {
d.writeShort(z);
} catch (Exception e) {
da.append(e.toString());
}
}
/**
* put an integer as an integer in the byte[]
*/
private void putInt(int z) {
try {
d.writeInt(z);
} catch (Exception e) {
da.appendDebug("slpMsgComposer::putInt()");
da.appendDebug(e);
}
}
private void putLong(long z) {
try {
d.writeLong(z);
} catch (Exception e) {
da.appendDebug("slpMsgComposer::putLong()");
da.appendDebug(e);
}
}
/**
* put URL entry in the byte[], assume "# of URL auths" is zero
*+---------------+---------------------------------+----------------+
*| Reserved | Lifetime | URL length |
*+---------------+---------------------------------+----------------+
*| URL len cont. | URL (variable length) \
*+---------------+--------------------------------------------------+
*| # of URL auths| Auth. blocks (if any) \
*+------------------------------------------------------------------+
*/
private void putURL(String url, int lifetime) {
try {
d.writeByte(0); // reserved
d.writeShort(lifetime); // lifetime
d.writeShort(url.length()); // len of URL
d.writeBytes(url); // URL string
d.writeByte(0); // # of authenticate
} catch (Exception e) {
da.append(e.toString());
}
}
/**
* calculate string length, precede with a short integer length field
*/
private int strlen(String s)
{
if (s != null)
{
return (2 + s.length());
}
return 2;
}
/**
* calculate URL-entry length, assume "# of url auths" is zero
*/
private int urllen(String url) {
return (6 + url.length());
}
/**
* service request <#1>
*+----------------------------+---------------------------+
*| Length of <PRList> | <PRList> string \
*+----------------------------+---------------------------+
*| Length of <service-type> | <service-type> string \
*+----------------------------+---------------------------+
*| Length of <scope-list> | <scope-list> string \
*+----------------------------+---------------------------+
*| Length of predicate string | service request predicate \
*+----------------------------+---------------------------+
*| Length of <SLP SPI> string | <SLP SPI> string \
*+----------------------------+---------------------------+
*/
public byte[] SrvRqst(int xid, int flag, String ltag, String pr,
String type, String scope, String pred, String spi) {
int len = Const.header_len + strlen(ltag) + strlen(pr) +
strlen(type) + strlen(scope) + strlen(pred) + strlen(spi);
Header(Const.SrvRqst, len, flag, xid);
putString(ltag); // language tag
putString(pr); // PRList
putString(type); // service type
putString(scope); // scope list
putString(pred); // predicate
putString(spi); // SPI
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVRQST MESSAGE" +
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- PRList = "+ pr +
"\n- Type = " + type +
"\n- Scope = " + scope +
"\n- Predicate = " + pred +
"\n- SPI = " + spi +
"\n");
return b.toByteArray();
}
/**
* service reply (reply for service request) <#2>
*+----------------------------+---------------------------+
*| Error Code | URL entry count |
*+----------------------------+---------------------------+
*| <URl entry 1> ... <URL entry N> \
*+----------------------------+---------------------------+
*/
public byte[] SrvReply(int xid, String ltag, byte[] buf) {
int len = Const.header_len + strlen(ltag) + buf.length;
Header(Const.SrvRply, len, Const.normal_flag, xid);
putString(ltag); // language tag
try {
d.write(buf, 0, buf.length); // ErrCode + #URL + each entry
} catch (Exception e) {
da.append(e.toString());
}
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVREPLY MESSAGE" +
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n");
// if (Const.OSGI_BUNDLE) daOSGi.visual_log("(PSM): SLP SERVICE DISCOVERY RESPONSE");
return b.toByteArray();
}
/**
* secure service reply (reply for secure service request) <#14>
*+----------------------------+---------------------------+
*| Error Code | URL entry count |
*+----------------------------+---------------------------+
*| <URl entry 1> ... <URL entry N> \
*+----------------------------+---------------------------+
*/
public byte[] SrvReplyAuth(int xid, String ltag, byte[] buf) {
int len = Const.header_len + strlen(ltag) + buf.length;
int ecode=0;
Header(Const.SrvRplyAuth, len, Const.normal_flag, xid);
putString(ltag); // language tag
try {
d.write(buf, 0, buf.length); // ErrCode + #URL + each entry
for (int i=0; i<2; i++) {
ecode <<= 8;
ecode += buf[i] & 0xff;
}
} catch (Exception e) {
da.appendDebug(e);
}
if (ecode==Const.AUTHENTICATION_FAILED) da.displayMessage ("Authentication Failed", Const.EXCLAMATION, "Authentication check");
if (ecode==Const.AUTHENTICATION_ABSENT) da.displayMessage ("Authentication Absent", Const.EXCLAMATION, "Authentication check");
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVREPLYAUTH MESSAGE" +
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Ecode= "+ ecode +
"\n");
// if (Const.OSGI_BUNDLE) daOSGi.visual_log("(PSM): SLP SERVICE DISCOVERY RESPONSE");
return b.toByteArray();
}
/**
* service registration <#3>
*+----------------------------------------------------------------+
*| <URL-Entry> \
*+---------------------------------+------------------------------+
*| Length of service type string | <service-type> \
*+---------------------------------+------------------------------+
*| Length of <scope-list> | <scope-list> \
*+---------------------------------+------------------------------+
*| Length of attr-list string | <attr-list> \
*+----------------+----------------+------------------------------+
*| # of AttrAuths | (if present) Attribute Authentication Blocks \
*+----------------+-----------------------------------------------+
*/
public byte[] SrvReg(int xid, int flag, String ltag, String url,
int lifetime, String type, String scope, String attr) {
int len = Const.header_len + strlen(ltag) + urllen(url) +
strlen(type) + strlen(scope) + strlen(attr) + 1;
Header(Const.SrvReg, len, flag, xid);
putString(ltag); // language tag
putURL(url, lifetime);
putString(type); // service type
putString(scope); // scope list
putString(attr); // attr list
putByte(0); // num of attrAuths
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVREG MESSAGE"+
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Type = " + type +
"\n- Scope = " + scope +
"\n- Url = " + url +
"\n- Lifetime = " + lifetime +
"\n- Attribute List = " + attr +
"\n");
return b.toByteArray();
}
/**
* service De-registration <#4>
*+-----------------------------+---------------------------+
*| Length of <scope-list> | <scope-list> \
*+-----------------------------+---------------------------+
*| <URL-entry> \
*+-----------------------------+---------------------------+
*| Length of <tag-list> | <tag-list> \
*+-----------------------------+---------------------------+
*/
public byte[] SrvDeReg(int xid, String ltag, String scope, String url,
int ltime, String tag) {
int len = Const.header_len + strlen(ltag) + strlen(scope) +
urllen(url) + strlen(tag);
Header(Const.SrvDeReg, len, Const.normal_flag, xid);
putString(ltag); // language tag
putString(scope); // scope list
putURL(url, ltime); // URL
putString(tag); // tag list
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVDEREG MESSAGE" +
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Scope = " + scope +
"\n- Url = " + url +
"\n- Tag List = " + tag +
"\n");
return b.toByteArray();
}
/**
* service ack (reply for SrvReg & SrvDeReg) <#5>
*+-----------------------------+
*| Error Code |
*+-----------------------------+
*/
public byte[] SrvAck(int xid, String ltag, int errcode) {
int len = Const.header_len + strlen(ltag) + 2;
Header(Const.SrvAck, len, Const.normal_flag, xid);
putString(ltag); // language tag
putShort(errcode); // ErrCode
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVACK MESSAGE" +
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Error = " + errcode +
"\n");
// if (Const.OSGI_BUNDLE) daOSGi.visual_log("(PSM): SLP SERVICE REGISTRATION ACK");
return b.toByteArray();
}
/**
* attribute request <#6>
*+-------------------------------+----------------------------+
*| Length of PRList | <PRList> string |
*+-------------------------------+----------------------------+
*| Length of URL | URL |
*+-------------------------------+----------------------------+
*| Length of <scope-list> | <scope-list> string |
*+-------------------------------+----------------------------+
*| Length of <tag-list> string | <tag-list> string |
*+-------------------------------+----------------------------+
*| Length of <SLP SPI> string | <SLP SPI> string |
*+-------------------------------+----------------------------+
*/
public byte[] AttrRqst(int xid, String ltag, String pr, String url,
String scope, String tag, String spi) {
int len = Const.header_len + strlen(ltag) + strlen(pr) +
strlen(url) + strlen(scope) + strlen(tag) + strlen(spi);
Header(Const.AttrRqst, len, Const.normal_flag, xid);
putString(ltag);
putString(pr);
putString(url);
putString(scope);
putString(tag);
putString(spi);
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING ATTRRQST MESSAGE"+
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- PRLIst = " + pr +
"\n- Url = " + url +
"\n- Scope = " + scope +
"\n- Tag List = " + tag +
"\n- SPI = " + spi +
"\n");
return b.toByteArray();
}
/**
* attribute reply (reply for attribute request) <#7>
*+-----------------------------+---------------------------------+
*| Error Code | Length of <attr-list> |
*+-----------------------------+---------------------------------+
*| <attr-list> \
*+----------------+----------------------------------------------+
*| # of AttrAuths | Attribute authentication block (if present) \
*+----------------+----------------------------------------------+
*/
public byte[] AttrReply(int xid, String ltag, int ecode, String buf) {
int len = Const.header_len + strlen(ltag) + 3 + strlen(buf);
Header(Const.AttrRply, len, Const.normal_flag, xid);
putString(ltag); // language tag
putShort(ecode); // ErrCode
putString(buf); // attr-list
putByte(0); // # of AttrAuths
if (Const.MESSAGE_LOG_ENABLED) {
if (Const.FORMAT_MESSAGE_LOG_ENABLED) {
String temp = "";
int i = 0;
StringTokenizer st = new StringTokenizer(buf,")");
while (st.hasMoreTokens()) {
if (i!=0)
temp += st.nextToken().substring(2) + "\n ";
else
temp += st.nextToken().substring(1) + "\n ";
i++;
}
buf = temp;
}
da.append("\nOUTGOING ATTRREPLY MESSAGE"+
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Error = " + ecode +
"\n- Attribute List = " + buf +
"\n");
}
return b.toByteArray();
}
/**
* directory agent advertisement <#8>
*+-------------------------------+--------------------------------+
*| Error Code | DA Stateless Boot Timestamp |
*+-------------------------------+--------------------------------+
*| DA Stateless Boot Time cont. | Length of URL |
*+-------------------------------+--------------------------------+
*| URL \
*+-------------------------------+--------------------------------+
*| Length of <scope-list> | <scope-list> \
*+-------------------------------+--------------------------------+
*| Length of <attr-list> | <attr-list> \
*+-------------------------------+--------------------------------+
*| Length of SLP <SPI> | SLP <SPI> string \
*+---------------+---------------+--------------------------------+
*| # Auth Blocks | Authentication blocl (if any) \
*+---------------+---------------+--------------------------------+
*/
public byte[] DAAdvert(int xid, int flag, String ltag, int ts,
String url, String scope, String attr, String spi) {
int len = Const.header_len + 7 + strlen(ltag) + strlen(url) +
strlen(scope) + strlen(attr) + strlen(spi);
Header(Const.DAAdvert, len, flag, xid);
putString(ltag); // language tag
putShort(0); // ErrCode
putInt(ts); // boot timestamp
putString(url); // URL
putString(scope); // scope list
putString(attr); // attribute list
putString(spi); // SLP SPI
putByte(0); // # Auth blocks
if (Const.MESSAGE_LOG_ENABLED && Const.DAAdvert_LOG_ENABLED) da.append("\nOUTGOING DAADVERT MESSAGE"+
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Boot TS = "+ ts +
"\n- Url = " + url +
"\n- Scope = " + scope +
"\n- Attribute List = " + attr +
"\n- SPI = " + spi +
"\n");
return b.toByteArray();
}
/**
* service type request <#9>
*+-------------------------------+-----------------------------+
*| Length of PRList | <PRList> string |
*+-------------------------------+-----------------------------+
*| Length of Naming Authority | <Naming Authority String> |
*+-------------------------------+-----------------------------+
*| Length of <scope-list> | <scope-list> string |
*+-------------------------------+-----------------------------+
*/
public byte[] SrvTypeRqst(int xid, String ltag, String pr, String na,
String scope) {
int len;
if (na.equals("-1")) {
len = Const.header_len + strlen(ltag) + strlen(pr) +
2 + strlen(scope);
} else {
len = Const.header_len + strlen(ltag) + strlen(pr) +
strlen(na) + strlen(scope);
}
Header(Const.SrvTypeRqst, len, Const.normal_flag, xid);
putString(ltag); // language tag
putString(pr); // PRList
if (na.equals("-1")) { // Naming Authority
putShort(0xFFFF); // -1 for all
} else {
putString(na);
}
putString(scope); // scope list
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVTYPERQST MESSAGE"+
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- PRList = " + pr +
"\n- Naming Authority = " + na +
"\n- Scope = " + scope +
"\n");
return b.toByteArray();
}
/**
* service type reply (reply for service type request) <#10>
*+-------------------------------+-------------------------------+
*| Error Code | Length of <srvType-list> |
*+-------------------------------+-------------------------------+
*| <srvType-list> \
*+---------------------------------------------------------------+
*/
public byte[] SrvTypeReply(int xid, String ltag, int ecode, String buf) {
int len = Const.header_len + strlen(ltag) + 2 + strlen(buf);
Header(Const.SrvTypeRply, len, Const.normal_flag, xid);
putString(ltag); // language tag
putShort(ecode); // ErrCode
putString(buf); // srvtype-list
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING SRVTYPEREPLY MESSAGE"+
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Error = " + ecode +
"\n- Type List = " + buf +
"\n");
return b.toByteArray();
}
/**
* DataRqst <#12> and DataRplyCmpl <#13> message
*+-------------------------------+-------------------------------+
*| Anti-entropy type ID | Number of Accept ID entries |
*+-------------------------------+-------------------------------+
*| Accept ID Entry 1 ... Accept ID Entry k \
*+---------------------------------------------------------------+
*/
public byte[] AntiEtrpRqst(int xid, String ltag, int type,
Vector adaList, Vector atsList) {
int size = 0;
for (int i=0; i<adaList.size(); i++) {
size += 10 + ((String)adaList.elementAt(i)).length();
}
int len = Const.header_len + strlen(ltag) + 4 + size;
Header(Const.AntiEtrpRqst, len, Const.normal_flag, xid);
putString(ltag); // language tag
putShort(type);
putShort(adaList.size());
for (int i=0; i<adaList.size(); i++) {
putLong(((Long)atsList.elementAt(i)).longValue());
putString((String)adaList.elementAt(i));
}
if (Const.MESSAGE_LOG_ENABLED) da.append("\nOUTGOING ANTIETRPRQST MESSAGE"+
"\n- Xid = "+ xid +
"\n- Ltag = "+ ltag +
"\n- Entropy Type = " + type +
"\n- ATS List = " + atsList.toString() +
"\n- ADA List = " + adaList.toString() +
"\n");
return b.toByteArray();
}
/**
* append MeshFwd extension & adjust original message
*+--------------------------------+----------------------------------+
*| MeshFwd Extension ID = 0x0006 | Next Extension Offset (NEO) |
*+--------------+-----------------+----------------------------------+
*| NEO Contd. | Fwd-ID | Version Timestamp |
*+--------------+-----------------+----------------------------------+
*| Version Timestamp, contd. |
*+--------------------------------+----------------------------------+
*| Version Timestamp, contd. | Accept ID \
*+--------------------------------+----------------------------------+
*/
public byte[] MeshFwdExt(byte[] buf, int id, long versionTS,
String ada, long ats) {
if (ada == null) {
//da.appendDebug("Null acceptDA!");
return buf;
}
int len = Util.parseInt(buf, 2, 3);
int alen = 14 + 10 + ada.length();
adjustMesg(buf, alen);
try {
b.reset();
d.write(buf, 0, len);
d.writeShort(Const.MeshFwdExt); // mesh-forwarding extension
d.writeShort(0); // next ext. offset
d.writeByte(0); // next ext. offset cont.
d.writeByte(id); // Fwd-ID
d.writeLong(versionTS); // version timestamp
d.writeLong(ats); // accept TS
d.writeShort(ada.length()); // length of accept DA URL
d.writeBytes(ada); // accept DA URL
} catch (Exception e) {
da.append(e.toString());
}
return b.toByteArray();
}
/**
* append Select extension & adjust original message
*+--------------------------------+----------------------------------+
*| Select Extension ID = 0x4002 | Next Extension Offset (NEO) |
*+--------------+-----------------+----------------+-----------------+
*| NEO Contd. | Number of URL Entries |
*+--------------+----------------------------------+
*/
public byte[] SelectExt(byte[] buf, int num) {
int len = Util.parseInt(buf, 2, 3);
int alen = 7;
adjustMesg(buf, alen);
try {
b.reset();
d.write(buf, 0, len);
d.writeShort(Const.SelectExt); // selection extension
d.writeShort(0); // next ext. offset
d.writeByte(0); // next ext. offset cont.
d.writeShort(num); // number of URL entries
} catch (Exception e) {
da.append(e.toString());
}
return b.toByteArray();
}
/**
* append Sort extension & adjust original message
*+--------------------------------+----------------------------------+
*| Sort Extension ID = 0x4003 | Next Extension Offset (NEO) |
*+--------------+-----------------+---------------+------------------+
*| NEO Contd. | Length of sort key list | sort key list \
*+--------------+---------------------------------+------------------+
*/
public byte[] SortExt(byte[] buf, String key) {
int len = Util.parseInt(buf, 2, 3);
int alen = 7 + key.length();
adjustMesg(buf, alen);
try {
b.reset();
d.write(buf, 0, len);
d.writeShort(Const.SortExt); // selection extension
d.writeShort(0); // next ext. offset
d.writeByte(0); // next ext. offset cont.
d.writeShort(key.length()); // length of key
d.writeBytes(key); // key string
} catch (Exception e) {
da.append(e.toString());
}
return b.toByteArray();
}
/**
* AttrList extension
*/
public byte[] AttrListExt(byte[] buf, Entry entry) {
int len = Util.parseInt(buf, 2, 3);
int alen = 10;
String url = "";
String attr = "";
if (entry != null) {
url = entry.getURL();
attr = entry.getAttr("");
alen += url.length() + attr.length();
}
adjustMesg(buf, alen);
try {
b.reset();
d.write(buf, 0, len);
d.writeShort(Const.AttrListExt); // AttrList extension
d.writeShort(0); // next ext. offset
d.writeByte(0); // next ext. offset cont.
putString(url);
putString(attr);
d.writeByte(0); // num auths
} catch (Exception e) {
da.append(e.toString());
}
return b.toByteArray();
}
/**
* adjust source message for the adding extension, need to change:
* (1) packet length (add new length)
* (2) last extension's NEO links to new one
*/
private void adjustMesg(byte[] buf, int alen) {
int plen = Util.parseInt(buf, 2, 3);
int nextExt = Util.parseInt(buf, 7, 3);
int lastExtAddr = 7;
while (nextExt != Const.EndOfExt) {
lastExtAddr = nextExt+2;
nextExt = Util.parseInt(buf, lastExtAddr, 3);
}
Util.writeInt(buf, lastExtAddr, plen, 3); // new ext. starting point
Util.writeInt(buf, 2, plen+alen, 3); // adjust message length
}
}
|