1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/* 2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use 3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of 5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government. 6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST 7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States 8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain. As a result, a formal 9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software. 10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly 12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED 13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF 14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT 15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY. NIST does not warrant or make any representations 16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but 17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of 18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software. 19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance 21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement 22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * . 24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.parser; 27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.InternalErrorHandler; 29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.stack.SIPStackTimerTask; 30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.*; 32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.*; 33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/** 35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Input class for the pipelined parser. Buffer all bytes read from the socket 36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and make them available to the message parser. 37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan (Contains a bug fix contributed by Rob Daugherty ( 39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Lucent Technologies) ) 40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * 41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */ 42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class Pipeline extends InputStream { 44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private LinkedList buffList; 45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private Buffer currentBuffer; 47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean isClosed; 49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private Timer timer; 51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private InputStream pipe; 53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private int readTimeout; 55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private TimerTask myTimerTask; 57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang class MyTimer extends SIPStackTimerTask { 59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Pipeline pipeline; 60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang private boolean isCancelled; 62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected MyTimer(Pipeline pipeline) { 64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.pipeline = pipeline; 65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang protected void runTask() { 68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isCancelled) 69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang pipeline.close(); 73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (IOException ex) { 74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang InternalErrorHandler.handleException(ex); 75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public boolean cancel() { 79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang boolean retval = super.cancel(); 80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isCancelled = true; 81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang class Buffer { 87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang byte[] bytes; 88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int length; 90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int ptr; 92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Buffer(byte[] bytes, int length) { 94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ptr = 0; 95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.length = length; 96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.bytes = bytes; 97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public int getNextByte() { 100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int retval = bytes[ptr++] & 0xFF; 101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void startTimer() { 107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.readTimeout == -1) 108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // TODO make this a tunable number. For now 4 seconds 110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // between reads seems reasonable upper limit. 111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.myTimerTask = new MyTimer(this); 112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timer.schedule(this.myTimerTask, this.readTimeout); 113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void stopTimer() { 116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.readTimeout == -1) 117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return; 118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.myTimerTask != null) 119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.myTimerTask.cancel(); 120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public Pipeline(InputStream pipe, int readTimeout, Timer timer) { 123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // pipe is the Socket stream 124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // this is recorded here to implement a timeout. 125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.timer = timer; 126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.pipe = pipe; 127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang buffList = new LinkedList(); 128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.readTimeout = readTimeout; 129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void write(byte[] bytes, int start, int length) throws IOException { 132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isClosed) 133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new IOException("Closed!!"); 134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Buffer buff = new Buffer(bytes, length); 135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang buff.ptr = start; 136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang synchronized (this.buffList) { 137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang buffList.add(buff); 138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang buffList.notifyAll(); 139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void write(byte[] bytes) throws IOException { 143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isClosed) 144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new IOException("Closed!!"); 145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang Buffer buff = new Buffer(bytes, bytes.length); 146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang synchronized (this.buffList) { 147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang buffList.add(buff); 148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang buffList.notifyAll(); 149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public void close() throws IOException { 153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.isClosed = true; 154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang synchronized (this.buffList) { 155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.buffList.notifyAll(); 156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // JvB: added 159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.pipe.close(); 160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang public int read() throws IOException { 163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // if (this.isClosed) return -1; 164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang synchronized (this.buffList) { 165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (currentBuffer != null 166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang && currentBuffer.ptr < currentBuffer.length) { 167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int retval = currentBuffer.getNextByte(); 168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (currentBuffer.ptr == currentBuffer.length) 169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.currentBuffer = null; 170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // Bug fix contributed by Rob Daugherty. 173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isClosed && this.buffList.isEmpty()) 174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return -1; 175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang try { 176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang // wait till something is posted. 177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang while (this.buffList.isEmpty()) { 178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.buffList.wait(); 179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (this.isClosed) 180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return -1; 181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang currentBuffer = (Buffer) this.buffList.removeFirst(); 183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang int retval = currentBuffer.getNextByte(); 184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang if (currentBuffer.ptr == currentBuffer.length) 185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang this.currentBuffer = null; 186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang return retval; 187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (InterruptedException ex) { 188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new IOException(ex.getMessage()); 189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } catch (NoSuchElementException ex) { 190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang ex.printStackTrace(); 191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang throw new IOException(ex.getMessage()); 192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang } 195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang 196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang} 197