001: // PushCacheHandler.java
002: // $Id: PushCacheHandler.java,v 1.2 2001/10/05 08:07:52 ylafon Exp $
003: // (c) COPYRIGHT MIT, INRIA and Keio, 2001.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.www.protocol.http.cache.push;
007:
008: import java.io.IOException;
009: import java.io.InputStream;
010: import java.io.DataInputStream;
011: import java.io.DataOutputStream;
012: import java.io.ByteArrayInputStream;
013: import java.io.ByteArrayOutputStream;
014:
015: import java.net.Socket;
016:
017: /**
018: * PushCacheHandler
019: *
020: * Created by PushCacheListener to handle a dialogue with a client
021: * @see PushCacheProtocol
022: *
023: * @author Paul Henshaw, The Fantastic Corporation, Paul.Henshaw@fantastic.com
024: * @version $Revision: 1.2 $
025: * $Id: PushCacheHandler.java,v 1.2 2001/10/05 08:07:52 ylafon Exp $
026: */
027: public class PushCacheHandler extends Thread {
028: private Socket _socket = null;
029: private boolean _running = false;
030: private InputStream _stream = null;
031: private byte[] _buffer = new byte[PushCacheProtocol.PACKET_LEN];
032: private byte[] _textBuffer = new byte[PushCacheProtocol.MAX_STRING_LEN];
033: private PushCacheListener _listener;
034:
035: DataInputStream _dataStream = null;
036:
037: /**
038: * Construct a PushCacheHandler
039: * @param socket Socket through which Handler will communicate with client
040: */
041: public PushCacheHandler(PushCacheListener l, Socket s)
042: throws IOException {
043: _listener = l;
044: _socket = s;
045: _stream = _socket.getInputStream();
046: _listener.registerHandler(this );
047: }
048:
049: /**
050: * Send an "OK" message back to client
051: */
052: protected void reply_ok() throws java.io.IOException {
053: byte[] ok = PushCacheProtocol.instance().okPacket();
054: _socket.getOutputStream().write(ok, 0, ok.length);
055: }
056:
057: /**
058: * Send a "NO" message back to client
059: */
060: protected void reply_no() throws java.io.IOException {
061: byte[] no = PushCacheProtocol.instance().noPacket();
062: _socket.getOutputStream().write(no, 0, no.length);
063: }
064:
065: /**
066: * Send an "ERR" message back to client
067: */
068: protected void reply_error(String message) {
069: try {
070: byte[] err = PushCacheProtocol.instance().errorPacket(
071: message);
072: _socket.getOutputStream().write(err, 0, err.length);
073: } catch (Exception e) {
074: e.printStackTrace();
075: }
076: }
077:
078: /**
079: * Request that Handler gracefully cease execution
080: */
081: public void stopRunning() {
082: try {
083: _running = false;
084: } catch (Exception e) {
085: e.printStackTrace();
086: }
087: }
088:
089: /**
090: * Close sockets, etc.
091: */
092: protected void cleanup() {
093: // System.err.println("PSLH: PushCacheHandler.cleanup()");
094: try {
095: // _socket.shutdownInput();
096: // _socket.shutdownOutput();
097: _socket.close();
098: _stream.close();
099: } catch (java.io.IOException e) {
100: // IGNORE
101: }
102: _socket = null;
103: _stream = null;
104: _listener.deregisterHandler(this );
105: }
106:
107: /**
108: * Debugging aid, displays buffer to stderr
109: */
110: public void printBuffer(byte[] buf, int len) {
111: byte b;
112: Integer myInt = new Integer(0);
113: int theInt = 0;
114:
115: System.err.println("buffer: ");
116:
117: for (int i = 0; i < len; i++) {
118: b = buf[i];
119:
120: if (!Character.isISOControl((char) b)) {
121: Character ch = new Character((char) b);
122: System.err.print(" " + ch.charValue() + " ");
123:
124: } else {
125:
126: theInt = 0xff & b;
127: if (theInt < 16) {
128: System.err.print("0" + myInt.toHexString(theInt)
129: + " ");
130: } else {
131: System.err.print(myInt.toHexString(theInt) + " ");
132: }
133: }
134: }
135: System.err.print("\n");
136: }
137:
138: /**
139: * Read data based on the contents of the remain_len field
140: */
141: protected void readPayload() throws IOException {
142: _dataStream.skipBytes(PushCacheProtocol.COMMAND_LEN);
143: int rlen = _dataStream.readInt();
144:
145: //System.err.println("Payload length="+rlen);
146:
147: if (rlen == 0) {
148: return;
149: }
150:
151: if (rlen > PushCacheProtocol.MAX_PAYLOAD_LEN) {
152: throw new IOException("Payload length " + rlen
153: + " exceeds maximum length "
154: + PushCacheProtocol.MAX_PAYLOAD_LEN);
155: }
156:
157: _textBuffer = new byte[rlen];
158:
159: int sofar = 0;
160: int toread = rlen;
161:
162: sofar = 0;
163: toread = rlen;
164: int rv = -1;
165: while (toread > 0) {
166: rv = _stream.read(_textBuffer, sofar, toread);
167: if (rv < 0) {
168: throw new IOException("read returned " + rv
169: + " after reading " + sofar + " bytes");
170: }
171: sofar += rv;
172: toread -= rv;
173: }
174: _dataStream = new DataInputStream(new ByteArrayInputStream(
175: _textBuffer));
176: }
177:
178: /**
179: * Handle "ADD" packet
180: */
181: protected void add() throws IOException {
182: int plen = _dataStream.readInt();
183: int ulen = _dataStream.readInt();
184:
185: if (plen == 0 || ulen == 0) {
186: throw new IOException(
187: "Zero length path or url in ADD command");
188: }
189:
190: if (plen > PushCacheProtocol.MAX_STRING_LEN
191: || ulen > PushCacheProtocol.MAX_STRING_LEN) {
192: throw new IOException("String too long in ADD command");
193: }
194:
195: /*
196: * Use new buffers to prevent issues with threads re-using
197: * them before PushCache has finished with them.
198: */
199: String path = new String(_textBuffer, 8, plen - 1);
200: String url = new String(_textBuffer, plen + 8, ulen - 1);
201:
202: /*
203: * Create forged reply for this file and store in cache
204: */
205: PushCacheManager.instance()
206: .storeReply(new PushReply(path, url));
207:
208: reply_ok();
209: }
210:
211: /**
212: * Handle "DEL" packet
213: */
214: protected void del() throws Exception {
215: String url = new String(_textBuffer, 0, _textBuffer.length - 1);
216: /*
217: * Create forged reply for this file and store in cache
218: */
219: PushCacheManager.instance().removeURL(url);
220:
221: reply_ok();
222: }
223:
224: /**
225: * Handle "CLN" packet
226: */
227: protected void clean() throws Exception {
228: PushCacheManager.instance().cleanCache();
229: reply_ok();
230: }
231:
232: /**
233: * Handle "PRS" packet
234: */
235: protected void present() throws Exception {
236: String url = new String(_textBuffer, 0, _textBuffer.length - 1);
237: if (PushCacheManager.instance().isPresent(url)) {
238: reply_ok();
239: } else {
240: reply_no();
241: }
242: }
243:
244: /**
245: * Handle "NOP" packet (reply OK)
246: */
247: protected void nop() throws Exception {
248: reply_ok();
249: }
250:
251: /**
252: * Handle dialogue with client
253: */
254: public void run() {
255: int done = 0;
256: int len = 0;
257: int off = 0;
258: int rv = 0;
259:
260: _running = true;
261:
262: try {
263: while (_running) {
264: // Read packet
265: rv = _stream.read(_buffer);
266:
267: // Check protocol tag
268: if (!PushCacheProtocol.instance().isValidProtocolTag(
269: _buffer)) {
270: throw new Exception("Bad protocol tag");
271: }
272:
273: // Use a DataInputStream to read bytes and shorts
274: _dataStream = new DataInputStream(
275: new ByteArrayInputStream(_buffer));
276: _dataStream.skipBytes(PushCacheProtocol.TAG_LEN);
277:
278: // Check protol version
279: short maj = _dataStream.readShort();
280: short min = _dataStream.readShort();
281: if (maj != PushCacheProtocol.MAJ_PROTO_VERSION
282: || min > PushCacheProtocol.MIN_PROTO_VERSION) {
283: throw new Exception("Bad protocol version");
284: }
285:
286: //
287: // Check command
288: // Note that check includes NULL characters they are
289: // part of the command.
290: //
291: String command = new String(_buffer,
292: PushCacheProtocol.HEADER_LEN,
293: PushCacheProtocol.COMMAND_LEN);
294: int com = PushCacheProtocol.instance().parseCommand(
295: command);
296: readPayload();
297:
298: switch (com) {
299: case PushCacheProtocol.ADD:
300: add();
301: break;
302:
303: case PushCacheProtocol.BYE:
304: stopRunning();
305: break;
306:
307: case PushCacheProtocol.DEL:
308: del();
309: break;
310:
311: case PushCacheProtocol.CLN:
312: clean();
313: break;
314:
315: case PushCacheProtocol.PRS:
316: present();
317: break;
318:
319: case PushCacheProtocol.NOP:
320: nop();
321: break;
322:
323: default:
324: throw new Exception("Unrecognised command \""
325: + command + "\"");
326: }
327: }
328: } catch (Exception e) {
329: e.printStackTrace();
330: _running = false;
331: reply_error(e.getMessage());
332: }
333: cleanup();
334: }
335: }
|