format (shendaras)

This commit is contained in:
shendaras
2004-04-10 11:50:11 +00:00
committed by zzz
parent 17a1b11f66
commit 51c49d7c1b
17 changed files with 1462 additions and 1464 deletions

View File

@ -1,4 +1,5 @@
package net.i2p.phttprelay;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
@ -44,70 +45,70 @@ import javax.servlet.http.HttpServletResponse;
*/
public class CheckSendStatusServlet extends PHTTPRelayServlet {
/* URL parameters on the check */
/** H(routerIdent).toBase64() of the target to receive the message */
public final static String PARAM_SEND_TARGET = "target";
public final static String PARAM_SEND_TARGET = "target";
/** msgId parameter */
public final static String PARAM_MSG_ID = "msgId";
public final static String PROP_STATUS = "status";
public final static String STATUS_PENDING = "pending";
public final static String STATUS_UNKNOWN = "unknown";
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String target = req.getParameter(PARAM_SEND_TARGET);
String msgIdStr = req.getParameter(PARAM_MSG_ID);
log("Checking status of [" + target + "] message [" + msgIdStr + "]");
if (!isKnownMessage(target, msgIdStr)) {
log("Not known - its not pending");
notPending(req, resp);
return;
} else {
log("Known - its still pending");
pending(req, resp);
return;
}
String target = req.getParameter(PARAM_SEND_TARGET);
String msgIdStr = req.getParameter(PARAM_MSG_ID);
log("Checking status of [" + target + "] message [" + msgIdStr + "]");
if (!isKnownMessage(target, msgIdStr)) {
log("Not known - its not pending");
notPending(req, resp);
return;
} else {
log("Known - its still pending");
pending(req, resp);
return;
}
}
private boolean isKnownMessage(String target, String msgId) throws IOException {
if ( (target == null) || (target.trim().length() <= 0) ) return false;
if ( (msgId == null) || (msgId.trim().length() <= 0) ) return false;
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
File msgFile = new File(identDir, "msg" + msgId + ".dat");
if (msgFile.exists())
return true;
else
return false;
} else {
return false;
}
} else {
return false;
}
if ((target == null) || (target.trim().length() <= 0)) return false;
if ((msgId == null) || (msgId.trim().length() <= 0)) return false;
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
File msgFile = new File(identDir, "msg" + msgId + ".dat");
if (msgFile.exists())
return true;
else
return false;
} else {
return false;
}
} else {
return false;
}
}
private void pending(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setStatus(HttpServletResponse.SC_OK);
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_PENDING).append('\n');
out.write(buf.toString().getBytes());
out.flush();
out.close();
resp.setStatus(HttpServletResponse.SC_OK);
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_PENDING).append('\n');
out.write(buf.toString().getBytes());
out.flush();
out.close();
}
private void notPending(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setStatus(HttpServletResponse.SC_OK);
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
out.write(buf.toString().getBytes());
out.flush();
out.close();
resp.setStatus(HttpServletResponse.SC_OK);
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
out.write(buf.toString().getBytes());
out.flush();
out.close();
}
}
}

View File

@ -1,4 +1,5 @@
package net.i2p.phttprelay;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
@ -18,23 +19,26 @@ import java.util.Set;
*/
class LockManager {
private volatile static Set _locks = new HashSet(); // target
public static void lockIdent(String target) {
while (true) {
synchronized (_locks) {
if (!_locks.contains(target)) {
_locks.add(target);
return;
}
try { _locks.wait(1000); } catch (InterruptedException ie) {}
}
}
while (true) {
synchronized (_locks) {
if (!_locks.contains(target)) {
_locks.add(target);
return;
}
try {
_locks.wait(1000);
} catch (InterruptedException ie) {
}
}
}
}
public static void unlockIdent(String target) {
synchronized (_locks) {
_locks.remove(target);
_locks.notifyAll();
}
synchronized (_locks) {
_locks.remove(target);
_locks.notifyAll();
}
}
}
}

View File

@ -1,4 +1,5 @@
package net.i2p.phttprelay;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
@ -25,49 +26,50 @@ abstract class PHTTPRelayServlet extends HttpServlet {
/* config params */
/*public final static String PARAM_BASEDIR = "baseDir";*/
public final static String ENV_BASEDIR = "phttpRelay.baseDir";
/** match the clock fudge factor on the router, rather than importing the entire router cvs module */
public final static long CLOCK_FUDGE_FACTOR = 1*60*1000;
public final static long CLOCK_FUDGE_FACTOR = 1 * 60 * 1000;
protected String buildURL(HttpServletRequest req, String path) {
StringBuffer buf = new StringBuffer();
buf.append(req.getScheme()).append("://");
buf.append(req.getServerName()).append(":").append(req.getServerPort());
buf.append(req.getContextPath());
buf.append(path);
log("URL built: " + buf.toString());
return buf.toString();
StringBuffer buf = new StringBuffer();
buf.append(req.getScheme()).append("://");
buf.append(req.getServerName()).append(":").append(req.getServerPort());
buf.append(req.getContextPath());
buf.append(path);
log("URL built: " + buf.toString());
return buf.toString();
}
protected File getIdentDir(String target) throws IOException {
if ( (_baseDir == null) || (target == null) ) throw new IOException("dir not specified to deal with");
File baseDir = new File(_baseDir);
if (!baseDir.exists()) {
boolean created = baseDir.mkdirs();
log("Creating PHTTP Relay Base Directory: " + baseDir.getAbsolutePath() + " - ok? " + created);
}
File identDir = new File(baseDir, target);
log("Ident dir: " + identDir.getAbsolutePath());
return identDir;
if ((_baseDir == null) || (target == null)) throw new IOException("dir not specified to deal with");
File baseDir = new File(_baseDir);
if (!baseDir.exists()) {
boolean created = baseDir.mkdirs();
log("Creating PHTTP Relay Base Directory: " + baseDir.getAbsolutePath() + " - ok? " + created);
}
File identDir = new File(baseDir, target);
log("Ident dir: " + identDir.getAbsolutePath());
return identDir;
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
String dir = System.getProperty(ENV_BASEDIR);
if (dir == null) {
_log.warn("Base directory for the polling http relay system not in the environment [" + ENV_BASEDIR +"]");
_log.warn("Setting the base directory to ./relayDir for " + getServletName());
_baseDir = ".relayDir";
} else {
_baseDir = dir;
log("Loaded up " + getServletName() + " with base directory " + _baseDir);
}
super.init(config);
String dir = System.getProperty(ENV_BASEDIR);
if (dir == null) {
_log.warn("Base directory for the polling http relay system not in the environment [" + ENV_BASEDIR + "]");
_log.warn("Setting the base directory to ./relayDir for " + getServletName());
_baseDir = ".relayDir";
} else {
_baseDir = dir;
log("Loaded up " + getServletName() + " with base directory " + _baseDir);
}
}
public void log(String msg) {
_log.debug(msg);
_log.debug(msg);
}
public void log(String msg, Throwable t) {
_log.debug(msg, t);
_log.debug(msg, t);
}
}
}

View File

@ -1,4 +1,5 @@
package net.i2p.phttprelay;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
@ -55,209 +56,208 @@ import net.i2p.util.Clock;
* baseDir is the directory under which registrants and their pending messages are stored
*
*/
public class PollServlet extends PHTTPRelayServlet {
public class PollServlet extends PHTTPRelayServlet {
/* URL parameters on the check */
/** H(routerIdent).toBase64() of the target to receive the message */
public final static String PARAM_SEND_TARGET = "target";
public final static String PARAM_SEND_TARGET = "target";
/** HTTP error code if the target is not known*/
public final static int CODE_UNKNOWN = HttpServletResponse.SC_NOT_FOUND;
/** HTTP error code if the signature failed */
public final static int CODE_UNAUTHORIZED = HttpServletResponse.SC_UNAUTHORIZED;
/** HTTP error code if everything is ok */
public final static int CODE_OK = HttpServletResponse.SC_OK;
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
byte data[] = getData(req);
if (data == null) return;
ByteArrayInputStream bais = new ByteArrayInputStream(data);
String target = getTarget(bais);
if (target == null) {
log("Target not specified");
resp.sendError(CODE_UNKNOWN);
return;
}
if (!isKnown(target)) {
resp.sendError(CODE_UNKNOWN);
return;
}
if (!isAuthorized(target, bais)) {
resp.sendError(CODE_UNAUTHORIZED);
return;
} else {
log("Authorized access for target " + target);
}
sendMessages(resp, target);
byte data[] = getData(req);
if (data == null) return;
ByteArrayInputStream bais = new ByteArrayInputStream(data);
String target = getTarget(bais);
if (target == null) {
log("Target not specified");
resp.sendError(CODE_UNKNOWN);
return;
}
if (!isKnown(target)) {
resp.sendError(CODE_UNKNOWN);
return;
}
if (!isAuthorized(target, bais)) {
resp.sendError(CODE_UNAUTHORIZED);
return;
} else {
log("Authorized access for target " + target);
}
sendMessages(resp, target);
}
private byte[] getData(HttpServletRequest req) throws ServletException, IOException {
ServletInputStream in = req.getInputStream();
int len = req.getContentLength();
byte data[] = new byte[len];
int cur = 0;
int read = DataHelper.read(in, data);
if (read != len) {
log("Size read is incorrect [" + read + " instead of expected " + len + "]");
return null;
} else {
log("Read data length: " + data.length + " in base64: " + Base64.encode(data));
return data;
}
ServletInputStream in = req.getInputStream();
int len = req.getContentLength();
byte data[] = new byte[len];
int cur = 0;
int read = DataHelper.read(in, data);
if (read != len) {
log("Size read is incorrect [" + read + " instead of expected " + len + "]");
return null;
} else {
log("Read data length: " + data.length + " in base64: " + Base64.encode(data));
return data;
}
}
private String getTarget(InputStream in) throws IOException {
StringBuffer buf = new StringBuffer(64);
int numBytes = 0;
int c = 0;
while ( (c = in.read()) != -1) {
if (c == (int)'&') break;
buf.append((char)c);
numBytes++;
if (numBytes > 128) {
log("Target didn't find the & after 128 bytes [" + buf.toString() + "]");
return null;
}
}
if (buf.toString().indexOf("target=") != 0) {
log("Did not start with target= [" + buf.toString() + "]");
return null;
}
return buf.substring("target=".length());
StringBuffer buf = new StringBuffer(64);
int numBytes = 0;
int c = 0;
while ((c = in.read()) != -1) {
if (c == (int) '&') break;
buf.append((char) c);
numBytes++;
if (numBytes > 128) {
log("Target didn't find the & after 128 bytes [" + buf.toString() + "]");
return null;
}
}
if (buf.toString().indexOf("target=") != 0) {
log("Did not start with target= [" + buf.toString() + "]");
return null;
}
return buf.substring("target=".length());
}
private void sendMessages(HttpServletResponse resp, String target) throws IOException {
log("Before lock " + target);
LockManager.lockIdent(target);
log("Locked " + target);
try {
File identDir = getIdentDir(target);
expire(identDir);
File messageFiles[] = identDir.listFiles();
resp.setStatus(CODE_OK);
log("Sending back " + (messageFiles.length -1) + " messages");
ServletOutputStream out = resp.getOutputStream();
DataHelper.writeDate(out, new Date(Clock.getInstance().now()));
DataHelper.writeLong(out, 2, messageFiles.length -1);
for (int i = 0; i < messageFiles.length; i++) {
if ("identity.dat".equals(messageFiles[i].getName())) {
// skip
} else {
log("Message file " + messageFiles[i].getName() + " is " + messageFiles[i].length() + " bytes");
DataHelper.writeLong(out, 4, messageFiles[i].length());
writeFile(out, messageFiles[i]);
boolean deleted = messageFiles[i].delete();
if (!deleted) {
log("!!!Error removing message file " + messageFiles[i].getAbsolutePath() + " - please delete!");
}
}
}
out.flush();
out.close();
} catch (DataFormatException dfe) {
log("Error sending message", dfe);
} finally {
LockManager.unlockIdent(target);
log("Unlocked " + target);
}
log("Before lock " + target);
LockManager.lockIdent(target);
log("Locked " + target);
try {
File identDir = getIdentDir(target);
expire(identDir);
File messageFiles[] = identDir.listFiles();
resp.setStatus(CODE_OK);
log("Sending back " + (messageFiles.length - 1) + " messages");
ServletOutputStream out = resp.getOutputStream();
DataHelper.writeDate(out, new Date(Clock.getInstance().now()));
DataHelper.writeLong(out, 2, messageFiles.length - 1);
for (int i = 0; i < messageFiles.length; i++) {
if ("identity.dat".equals(messageFiles[i].getName())) {
// skip
} else {
log("Message file " + messageFiles[i].getName() + " is " + messageFiles[i].length() + " bytes");
DataHelper.writeLong(out, 4, messageFiles[i].length());
writeFile(out, messageFiles[i]);
boolean deleted = messageFiles[i].delete();
if (!deleted) {
log("!!!Error removing message file " + messageFiles[i].getAbsolutePath() + " - please delete!");
}
}
}
out.flush();
out.close();
} catch (DataFormatException dfe) {
log("Error sending message", dfe);
} finally {
LockManager.unlockIdent(target);
log("Unlocked " + target);
}
}
private final static long EXPIRE_DELAY = 60*1000; // expire messages every minute
private final static long EXPIRE_DELAY = 60 * 1000; // expire messages every minute
private void expire(File identDir) throws IOException {
File files[] = identDir.listFiles();
long now = System.currentTimeMillis();
for (int i = 0 ; i < files.length; i++) {
if ("identity.dat".equals(files[i].getName())) {
continue;
}
if (files[i].lastModified() + EXPIRE_DELAY < now) {
log("Expiring " + files[i].getAbsolutePath());
files[i].delete();
}
}
File files[] = identDir.listFiles();
long now = System.currentTimeMillis();
for (int i = 0; i < files.length; i++) {
if ("identity.dat".equals(files[i].getName())) {
continue;
}
if (files[i].lastModified() + EXPIRE_DELAY < now) {
log("Expiring " + files[i].getAbsolutePath());
files[i].delete();
}
}
}
private void writeFile(ServletOutputStream out, File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
try {
byte buf[] = new byte[4096];
while (true) {
int read = DataHelper.read(fis, buf);
if (read > 0)
out.write(buf, 0, read);
else
break;
}
} finally {
fis.close();
}
FileInputStream fis = new FileInputStream(file);
try {
byte buf[] = new byte[4096];
while (true) {
int read = DataHelper.read(fis, buf);
if (read > 0)
out.write(buf, 0, read);
else
break;
}
} finally {
fis.close();
}
}
private boolean isKnown(String target) throws IOException {
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
return true;
} else {
return false;
}
} else {
return false;
}
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
return true;
} else {
return false;
}
} else {
return false;
}
}
private boolean isAuthorized(String target, InputStream in) throws IOException {
RouterIdentity ident = null;
try {
ident = getRouterIdentity(target);
} catch (DataFormatException dfe) {
log("Identity was not valid", dfe);
}
if (ident == null) {
log("Identity not registered");
return false;
}
try {
long val = DataHelper.readLong(in, 4);
Signature sig = new Signature();
sig.readBytes(in);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataHelper.writeLong(baos, 4, val);
if (DSAEngine.getInstance().verifySignature(sig, baos.toByteArray(), ident.getSigningPublicKey())) {
return true;
} else {
log("Signature does NOT match");
return false;
}
} catch (DataFormatException dfe) {
log("Format error reading the nonce and signature", dfe);
return false;
}
RouterIdentity ident = null;
try {
ident = getRouterIdentity(target);
} catch (DataFormatException dfe) {
log("Identity was not valid", dfe);
}
if (ident == null) {
log("Identity not registered");
return false;
}
try {
long val = DataHelper.readLong(in, 4);
Signature sig = new Signature();
sig.readBytes(in);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataHelper.writeLong(baos, 4, val);
if (DSAEngine.getInstance().verifySignature(sig, baos.toByteArray(), ident.getSigningPublicKey())) {
return true;
} else {
log("Signature does NOT match");
return false;
}
} catch (DataFormatException dfe) {
log("Format error reading the nonce and signature", dfe);
return false;
}
}
private RouterIdentity getRouterIdentity(String target) throws IOException, DataFormatException {
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
RouterIdentity ident = new RouterIdentity();
ident.readBytes(new FileInputStream(identFile));
return ident;
} else {
return null;
}
} else {
return null;
}
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
RouterIdentity ident = new RouterIdentity();
ident.readBytes(new FileInputStream(identFile));
return ident;
} else {
return null;
}
} else {
return null;
}
}
}
}

View File

@ -1,4 +1,5 @@
package net.i2p.phttprelay;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
@ -66,89 +67,92 @@ public class RegisterServlet extends PHTTPRelayServlet {
/* config params */
public final static String PARAM_POLL_PATH = "pollPath";
public final static String PARAM_SEND_PATH = "sendPath";
/* key=val keys sent back on registration */
public final static String PROP_STATUS = "status";
public final static String PROP_STATUS = "status";
public final static String PROP_POLL_URL = "pollURL";
public final static String PROP_SEND_URL = "sendURL";
public final static String PROP_TIME_OFFSET = "timeOffset"; // ms (local-remote)
/* values for the PROP_STATUS */
public final static String STATUS_FAILED = "failed";
public final static String STATUS_FAILED = "failed";
public final static String STATUS_REGISTERED = "registered";
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletInputStream in = req.getInputStream();
RouterIdentity ident = new RouterIdentity();
try {
Date remoteTime = DataHelper.readDate(in);
long skew = getSkew(remoteTime);
ident.readBytes(in);
boolean ok = registerIdent(ident);
sendURLs(req, resp, skew, ok);
} catch (DataFormatException dfe) {
log("Invalid format for router identity posted", dfe);
} finally {
in.close();
}
}
private long getSkew(Date remoteDate) {
if (remoteDate == null) {
log("*ERROR: remote date was null");
return Long.MAX_VALUE;
} else {
long diff = Clock.getInstance().now() - remoteDate.getTime();
return diff;
}
}
private boolean registerIdent(RouterIdentity ident) throws DataFormatException, IOException {
File identDir = getIdentDir(ident.getHash().toBase64());
boolean created = identDir.mkdirs();
File identFile = new File(identDir, "identity.dat");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(identFile);
ident.writeBytes(fos);
} finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
}
log("Identity registered into " + identFile.getAbsolutePath());
return true;
}
private void sendURLs(HttpServletRequest req, HttpServletResponse resp, long skew, boolean ok) throws IOException {
ServletOutputStream out = resp.getOutputStream();
log("*Debug: clock skew of " + skew + "ms (local-remote)");
StringBuffer buf = new StringBuffer();
if (ok) {
buf.append(PROP_POLL_URL).append("=").append(buildURL(req, _pollPath)).append("\n");
buf.append(PROP_SEND_URL).append("=").append(buildURL(req, _sendPath)).append("\n");
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
buf.append(PROP_STATUS).append("=").append(STATUS_REGISTERED).append("\n");
} else {
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
buf.append(PROP_STATUS).append("=").append(STATUS_FAILED).append("\n");
}
out.write(buf.toString().getBytes());
out.close();
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletInputStream in = req.getInputStream();
RouterIdentity ident = new RouterIdentity();
try {
Date remoteTime = DataHelper.readDate(in);
long skew = getSkew(remoteTime);
ident.readBytes(in);
boolean ok = registerIdent(ident);
sendURLs(req, resp, skew, ok);
} catch (DataFormatException dfe) {
log("Invalid format for router identity posted", dfe);
} finally {
in.close();
}
}
private long getSkew(Date remoteDate) {
if (remoteDate == null) {
log("*ERROR: remote date was null");
return Long.MAX_VALUE;
} else {
long diff = Clock.getInstance().now() - remoteDate.getTime();
return diff;
}
}
private boolean registerIdent(RouterIdentity ident) throws DataFormatException, IOException {
File identDir = getIdentDir(ident.getHash().toBase64());
boolean created = identDir.mkdirs();
File identFile = new File(identDir, "identity.dat");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(identFile);
ident.writeBytes(fos);
} finally {
if (fos != null) try {
fos.close();
} catch (IOException ioe) {
}
}
log("Identity registered into " + identFile.getAbsolutePath());
return true;
}
private void sendURLs(HttpServletRequest req, HttpServletResponse resp, long skew, boolean ok) throws IOException {
ServletOutputStream out = resp.getOutputStream();
log("*Debug: clock skew of " + skew + "ms (local-remote)");
StringBuffer buf = new StringBuffer();
if (ok) {
buf.append(PROP_POLL_URL).append("=").append(buildURL(req, _pollPath)).append("\n");
buf.append(PROP_SEND_URL).append("=").append(buildURL(req, _sendPath)).append("\n");
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
buf.append(PROP_STATUS).append("=").append(STATUS_REGISTERED).append("\n");
} else {
buf.append(PROP_TIME_OFFSET).append("=").append(skew).append("\n");
buf.append(PROP_STATUS).append("=").append(STATUS_FAILED).append("\n");
}
out.write(buf.toString().getBytes());
out.close();
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
String pollPath = config.getInitParameter(PARAM_POLL_PATH);
if (pollPath == null)
throw new ServletException("Polling path for the registration servlet required [" + PARAM_POLL_PATH + "]");
else
_pollPath = pollPath;
String sendPath = config.getInitParameter(PARAM_SEND_PATH);
if (sendPath == null)
throw new ServletException("Sending path for the registration servlet required [" + PARAM_SEND_PATH + "]");
else
_sendPath = sendPath;
super.init(config);
String pollPath = config.getInitParameter(PARAM_POLL_PATH);
if (pollPath == null)
throw new ServletException("Polling path for the registration servlet required [" + PARAM_POLL_PATH + "]");
else
_pollPath = pollPath;
String sendPath = config.getInitParameter(PARAM_SEND_PATH);
if (sendPath == null)
throw new ServletException("Sending path for the registration servlet required [" + PARAM_SEND_PATH + "]");
else
_sendPath = sendPath;
}
}
}

View File

@ -1,4 +1,5 @@
package net.i2p.phttprelay;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
@ -63,256 +64,261 @@ import javax.servlet.http.HttpServletResponse;
public class SendServlet extends PHTTPRelayServlet {
private String _checkPath;
private int _maxMessagesPerIdent;
/* config params */
public final static String PARAM_CHECK_PATH = "checkPath";
public final static String PARAM_MAX_MESSAGES_PER_IDENT = "maxMessagesPerIdent";
/* URL parameters on the send */
/** H(routerIdent).toBase64() of the target to receive the message */
public final static String PARAM_SEND_TARGET = "target";
public final static String PARAM_SEND_TARGET = "target";
/** # ms to wait for the message to be delivered before failing it */
public final static String PARAM_SEND_TIMEOUTMS = "timeoutMs";
/** # bytes to be sent in the message */
public final static String PARAM_SEND_DATA_LENGTH = "dataLength";
/** sending router's time in ms */
public final static String PARAM_SEND_TIME = "localTime";
/** msgId parameter to access the check path servlet with (along side PARAM_SEND_TARGET) */
public final static String PARAM_MSG_ID = "msgId";
/* key=val keys sent back on registration */
public final static String PROP_CHECK_URL = "statusCheckURL";
public final static String PROP_STATUS = "status";
public final static String STATUS_OK = "accepted";
public final static String STATUS_UNKNOWN = "unknown";
private final static String STATUS_CLOCKSKEW = "clockSkew_"; /** prefix for (local-remote) */
private final static String STATUS_CLOCKSKEW = "clockSkew_";
/** prefix for (local-remote) */
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletInputStream in = req.getInputStream();
try {
int contentLen = req.getContentLength();
String firstLine = getFirstLine(in, contentLen);
if (firstLine == null) {
return;
}
Map params = getParameters(firstLine);
String target = (String)params.get(PARAM_SEND_TARGET);
String timeoutStr = (String)params.get(PARAM_SEND_TIMEOUTMS);
String lenStr = (String)params.get(PARAM_SEND_DATA_LENGTH);
String remoteTimeStr = (String)params.get(PARAM_SEND_TIME);
long skew = 0;
try {
long remTime = Long.parseLong(remoteTimeStr);
skew = System.currentTimeMillis() - remTime;
} catch (Throwable t) {
skew = Long.MAX_VALUE;
log("*ERROR could not parse the remote time from [" + remoteTimeStr + "]");
}
ServletInputStream in = req.getInputStream();
try {
int contentLen = req.getContentLength();
String firstLine = getFirstLine(in, contentLen);
if (firstLine == null) { return; }
Map params = getParameters(firstLine);
String target = (String) params.get(PARAM_SEND_TARGET);
String timeoutStr = (String) params.get(PARAM_SEND_TIMEOUTMS);
String lenStr = (String) params.get(PARAM_SEND_DATA_LENGTH);
String remoteTimeStr = (String) params.get(PARAM_SEND_TIME);
long skew = 0;
try {
long remTime = Long.parseLong(remoteTimeStr);
skew = System.currentTimeMillis() - remTime;
} catch (Throwable t) {
skew = Long.MAX_VALUE;
log("*ERROR could not parse the remote time from [" + remoteTimeStr + "]");
}
log("Target [" + target + "] timeout [" + timeoutStr + "] length [" + lenStr + "] skew [" + skew + "]");
log("Target [" + target + "] timeout [" + timeoutStr + "] length [" + lenStr + "] skew [" + skew + "]");
if ( (skew > CLOCK_FUDGE_FACTOR) || (skew < 0 - CLOCK_FUDGE_FACTOR) ) {
log("Attempt to send by a skewed router: skew = " + skew + "ms (local-remote)");
failSkewed(req, resp, skew);
}
if (!isValidTarget(target)) {
log("Attempt to send to an invalid target [" + target + "]");
fail(req, resp, "Unknown or invalid target");
return;
}
if ((skew > CLOCK_FUDGE_FACTOR) || (skew < 0 - CLOCK_FUDGE_FACTOR)) {
log("Attempt to send by a skewed router: skew = " + skew + "ms (local-remote)");
failSkewed(req, resp, skew);
}
long len = -1;
try {
len = Long.parseLong(lenStr);
} catch (Throwable t) {
log("Unable to parse length parameter [" + PARAM_SEND_DATA_LENGTH + "] (" + lenStr + ")");
fail(req, resp, "Invalid length parameter");
return;
}
if (!isValidTarget(target)) {
log("Attempt to send to an invalid target [" + target + "]");
fail(req, resp, "Unknown or invalid target");
return;
}
int msgId = saveFile(in, resp, target, len);
if (msgId >= 0) {
sendSuccess(req, resp, target, msgId);
} else {
fail(req, resp, "Unable to queue up the message for delivery");
}
} finally {
try { in.close(); } catch (IOException ioe) {}
}
long len = -1;
try {
len = Long.parseLong(lenStr);
} catch (Throwable t) {
log("Unable to parse length parameter [" + PARAM_SEND_DATA_LENGTH + "] (" + lenStr + ")");
fail(req, resp, "Invalid length parameter");
return;
}
int msgId = saveFile(in, resp, target, len);
if (msgId >= 0) {
sendSuccess(req, resp, target, msgId);
} else {
fail(req, resp, "Unable to queue up the message for delivery");
}
} finally {
try {
in.close();
} catch (IOException ioe) {
}
}
}
private String getFirstLine(ServletInputStream in, int len) throws ServletException, IOException {
StringBuffer buf = new StringBuffer(128);
int numBytes = 0;
int c = 0;
while ( (c = in.read()) != -1) {
if (c == (int)'\n') break;
buf.append((char)c);
numBytes++;
if (numBytes > 512) {
log("First line is > 512 bytes [" + buf.toString() + "]");
return null;
}
}
log("First line: " + buf.toString());
return buf.toString();
StringBuffer buf = new StringBuffer(128);
int numBytes = 0;
int c = 0;
while ((c = in.read()) != -1) {
if (c == (int) '\n') break;
buf.append((char) c);
numBytes++;
if (numBytes > 512) {
log("First line is > 512 bytes [" + buf.toString() + "]");
return null;
}
}
log("First line: " + buf.toString());
return buf.toString();
}
private static Map getParameters(String line) {
//StringTokenizer tok = new StringTokenizer(line, "&=", true);
Map params = new HashMap();
while (line != null) {
String key = null;
String val = null;
int firstAmp = line.indexOf('&');
int firstEq = line.indexOf('=');
if (firstAmp > 0) {
key = line.substring(0, firstEq);
val = line.substring(firstEq+1, firstAmp);
line = line.substring(firstAmp+1);
params.put(key, val);
} else {
line = null;
}
}
return params;
//StringTokenizer tok = new StringTokenizer(line, "&=", true);
Map params = new HashMap();
while (line != null) {
String key = null;
String val = null;
int firstAmp = line.indexOf('&');
int firstEq = line.indexOf('=');
if (firstAmp > 0) {
key = line.substring(0, firstEq);
val = line.substring(firstEq + 1, firstAmp);
line = line.substring(firstAmp + 1);
params.put(key, val);
} else {
line = null;
}
}
return params;
}
private boolean isValidTarget(String target) throws IOException {
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
String files[] = identDir.list();
// we skip 1 because of identity.dat
if (files.length -1 > _maxMessagesPerIdent) {
log("Too many messages pending for " + target + ": " + (files.length-1));
return false;
} else {
return true;
}
} else {
log("Ident directory exists, but identity does not... corrupt for " + target);
return false;
}
} else {
log("Unknown ident " + target);
return false;
}
File identDir = getIdentDir(target);
if (identDir.exists()) {
File identFile = new File(identDir, "identity.dat");
if (identFile.exists()) {
// known and valid (maybe we need to check the file format... naw, fuck it
String files[] = identDir.list();
// we skip 1 because of identity.dat
if (files.length - 1 > _maxMessagesPerIdent) {
log("Too many messages pending for " + target + ": " + (files.length - 1));
return false;
} else {
return true;
}
} else {
log("Ident directory exists, but identity does not... corrupt for " + target);
return false;
}
} else {
log("Unknown ident " + target);
return false;
}
}
private int saveFile(InputStream in, HttpServletResponse resp, String target, long len) throws IOException {
File identDir = getIdentDir(target);
if (!identDir.exists()) return -1;
try {
LockManager.lockIdent(target);
int i = 0;
while (true) {
File curFile = new File(identDir, "msg" + i + ".dat");
if (!curFile.exists()) {
boolean ok = writeFile(curFile, in, len);
if (ok)
return i;
else
return -1;
}
i++;
continue;
}
} finally {
LockManager.unlockIdent(target);
}
File identDir = getIdentDir(target);
if (!identDir.exists()) return -1;
try {
LockManager.lockIdent(target);
int i = 0;
while (true) {
File curFile = new File(identDir, "msg" + i + ".dat");
if (!curFile.exists()) {
boolean ok = writeFile(curFile, in, len);
if (ok)
return i;
else
return -1;
}
i++;
continue;
}
} finally {
LockManager.unlockIdent(target);
}
}
private boolean writeFile(File file, InputStream in, long len) throws IOException {
long remaining = len;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
byte buf[] = new byte[4096];
while (remaining > 0) {
int read = in.read(buf);
if (read == -1)
break;
remaining -= read;
if (read > 0)
fos.write(buf, 0, read);
}
} finally {
if (fos != null) {
try { fos.close(); } catch (IOException ioe) {}
}
if (remaining != 0) {
log("Invalid remaining bytes [" + remaining + " out of " + len + "] - perhaps message was cancelled partway through delivery? deleting " + file.getAbsolutePath());
boolean deleted = file.delete();
if (!deleted)
log("!!!Error deleting temporary file " + file.getAbsolutePath());
return false;
}
}
return true;
long remaining = len;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
byte buf[] = new byte[4096];
while (remaining > 0) {
int read = in.read(buf);
if (read == -1) break;
remaining -= read;
if (read > 0) fos.write(buf, 0, read);
}
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException ioe) {
}
}
if (remaining != 0) {
log("Invalid remaining bytes [" + remaining + " out of " + len
+ "] - perhaps message was cancelled partway through delivery? deleting " + file.getAbsolutePath());
boolean deleted = file.delete();
if (!deleted) log("!!!Error deleting temporary file " + file.getAbsolutePath());
return false;
}
}
return true;
}
private void sendSuccess(HttpServletRequest req, HttpServletResponse resp, String target, int msgId) throws IOException {
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_OK).append('\n');
buf.append(PROP_CHECK_URL).append('=').append(buildURL(req, _checkPath));
buf.append('?');
buf.append(PARAM_SEND_TARGET).append('=').append(target).append("&");
buf.append(PARAM_MSG_ID).append('=').append(msgId).append("\n");
out.write(buf.toString().getBytes());
out.flush();
private void sendSuccess(HttpServletRequest req, HttpServletResponse resp, String target, int msgId)
throws IOException {
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_OK).append('\n');
buf.append(PROP_CHECK_URL).append('=').append(buildURL(req, _checkPath));
buf.append('?');
buf.append(PARAM_SEND_TARGET).append('=').append(target).append("&");
buf.append(PARAM_MSG_ID).append('=').append(msgId).append("\n");
out.write(buf.toString().getBytes());
out.flush();
}
private void fail(HttpServletRequest req, HttpServletResponse resp, String err) throws IOException {
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
out.write(buf.toString().getBytes());
out.flush();
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_UNKNOWN).append('\n');
out.write(buf.toString().getBytes());
out.flush();
}
private void failSkewed(HttpServletRequest req, HttpServletResponse resp, long skew) throws IOException {
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_CLOCKSKEW).append(skew).append('\n');
out.write(buf.toString().getBytes());
out.flush();
ServletOutputStream out = resp.getOutputStream();
StringBuffer buf = new StringBuffer();
buf.append(PROP_STATUS).append('=').append(STATUS_CLOCKSKEW).append(skew).append('\n');
out.write(buf.toString().getBytes());
out.flush();
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
String checkPath = config.getInitParameter(PARAM_CHECK_PATH);
if (checkPath == null)
throw new ServletException("Check status path for the sending servlet required [" + PARAM_CHECK_PATH + "]");
else
_checkPath = checkPath;
String maxMessagesPerIdentStr = config.getInitParameter(PARAM_MAX_MESSAGES_PER_IDENT);
if (maxMessagesPerIdentStr == null)
throw new ServletException("Max messages per ident for the sending servlet required [" + PARAM_MAX_MESSAGES_PER_IDENT + "]");
try {
_maxMessagesPerIdent = Integer.parseInt(maxMessagesPerIdentStr);
} catch (Throwable t) {
throw new ServletException("Valid max messages per ident for the sending servlet required [" + PARAM_MAX_MESSAGES_PER_IDENT + "]");
}
super.init(config);
String checkPath = config.getInitParameter(PARAM_CHECK_PATH);
if (checkPath == null)
throw new ServletException("Check status path for the sending servlet required [" + PARAM_CHECK_PATH + "]");
else
_checkPath = checkPath;
String maxMessagesPerIdentStr = config.getInitParameter(PARAM_MAX_MESSAGES_PER_IDENT);
if (maxMessagesPerIdentStr == null)
throw new ServletException("Max messages per ident for the sending servlet required ["
+ PARAM_MAX_MESSAGES_PER_IDENT + "]");
try {
_maxMessagesPerIdent = Integer.parseInt(maxMessagesPerIdentStr);
} catch (Throwable t) {
throw new ServletException("Valid max messages per ident for the sending servlet required ["
+ PARAM_MAX_MESSAGES_PER_IDENT + "]");
}
}
public static void main(String args[]) {
String line = "target=pp0ARjQiB~IKC-0FsMUsPEMrwR3gxVBZGRYfEr1IzHI=&timeoutMs=52068&dataLength=2691&";
Map props = getParameters(line);
for (java.util.Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
String key = (String)iter.next();
String val = (String)props.get(key);
System.out.println("[" + key + "] = [" + val + "]");
}
String line = "target=pp0ARjQiB~IKC-0FsMUsPEMrwR3gxVBZGRYfEr1IzHI=&timeoutMs=52068&dataLength=2691&";
Map props = getParameters(line);
for (java.util.Iterator iter = props.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
String val = (String) props.get(key);
System.out.println("[" + key + "] = [" + val + "]");
}
}
}
}