00001 00002 package protocol; 00003 00004 import utils.Log; 00005 import utils.OctetBuffer; 00006 00007 /** 00008 * Represents a Protocol Data Unit (PDU). 00009 * 00010 * <pre> 00011 * 1 2 3 00012 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 Octets: 00013 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +---------------+ 00014 * |1| Source Call Number |0| Destination Call Number | 0 1 2 3 00015 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +---------------+ 00016 * | Time-Stamp | 4 5 6 7 00017 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +---------------+ 00018 * | Out Seq No | In Seq No |0| PDU Type | Sub Class | 8 9 10 11 00019 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +---------------+ 00020 * | | 12 ... 00021 * : Payload : 00022 * | | 00023 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00024 * </pre> 00025 * 00026 */ 00027 public abstract class ProtocolDataUnit 00028 { 00029 /** PDU Type: Data Audio Compression Format Raw Voice Data */ 00030 protected final static int VOICE = 0x02; 00031 00032 /** The call object */ 00033 protected CallContext call; 00034 00035 /** The payload data */ 00036 protected OctetBuffer payload; 00037 00038 /** The time-stamp */ 00039 protected Long timeStamp; 00040 00041 /** The source call number */ 00042 protected int sourceCallNumber; 00043 00044 /** The destination call number */ 00045 protected int destinationCallNumber; 00046 00047 /** The outbound stream sequence number */ 00048 protected int outSeqNo; 00049 00050 /** The inbound stream sequence number */ 00051 protected int inSeqNo; 00052 00053 /** The frame type */ 00054 protected int pduType; 00055 00056 /** The subclass */ 00057 protected int pduSubclass; 00058 00059 /** 00060 * The constructor for outbound PDUs. 00061 * 00062 * @param call The Call object 00063 */ 00064 public ProtocolDataUnit( CallContext call ) 00065 { 00066 this.call = call; 00067 00068 this.destinationCallNumber = call.getDestinationCallNumber (); 00069 this.sourceCallNumber = call.getSourceCallNumber (); 00070 00071 this.setTimestamp( call.getTimestamp () ); 00072 } 00073 00074 /** 00075 * The constructor for inbound PDUs. 00076 * 00077 * @param call The Call object 00078 * @param pduOctets The incoming message bytes 00079 */ 00080 public ProtocolDataUnit( CallContext call, byte[] pduOctets ) 00081 { 00082 this.call = call; 00083 00084 OctetBuffer buf = OctetBuffer.wrap( pduOctets ); 00085 00086 this.sourceCallNumber = buf.getShort (); 00087 this.sourceCallNumber &= 0x7FFF; // strip F bit 00088 00089 this.destinationCallNumber = buf.getShort(); 00090 this.destinationCallNumber &= 0x7FFF; // strip R bit 00091 00092 this.setTimestamp( ( buf.getInt () + 0x100000000L ) & 0xFFFFFFFFL ); 00093 00094 this.outSeqNo = OctetBuffer.toInt( buf.get() ); 00095 this.inSeqNo = OctetBuffer.toInt( buf.get() ); 00096 00097 this.pduType = OctetBuffer.toInt( buf.get() ); 00098 this.pduSubclass = OctetBuffer.toInt( buf.get() ); 00099 00100 this.payload = buf.slice (); 00101 } 00102 00103 /** 00104 * Sets the time stamp as long. 00105 */ 00106 void setTimestamp( long v ) 00107 { 00108 this.timeStamp = new Long( v ); 00109 } 00110 00111 /** 00112 * Returns the timestamp as long. 00113 */ 00114 long getTimestamp () 00115 { 00116 return this.timeStamp != null ? this.timeStamp.longValue () : 0; 00117 } 00118 00119 /** 00120 * Creates a new PDU of the correct type. 00121 * 00122 * @param call Call 00123 * @param pduOctets byte[] 00124 * @return a PDU 00125 */ 00126 public static ProtocolDataUnit create( CallContext call, byte[] pduOctets ) 00127 { 00128 if ( pduOctets == null || pduOctets.length < 12 ) { 00129 return null; 00130 } 00131 00132 ProtocolDataUnit pdu = null; 00133 00134 int pduType = OctetBuffer.toInt( pduOctets[10] ); 00135 00136 switch ( pduType ) 00137 { 00138 case VOICE: 00139 pdu = new VoicePDU( call, pduOctets ); 00140 break; 00141 default: 00142 Log.warn( "Unknown PDU type " + pduType ); 00143 pdu = new ProtocolDataUnit( call, pduOctets ) {}; 00144 break; 00145 } 00146 00147 return pdu; 00148 } 00149 00150 /** 00151 * Sends a specified payload. Payload represents the data field in 00152 * the frame. 00153 * 00154 * @param payload The payload data 00155 */ 00156 public void sendPayload( byte[] payload ) 00157 { 00158 this.outSeqNo = this.call.getOutSeqNoInc(); 00159 this.inSeqNo = this.call.getInSeqNo(); 00160 00161 OctetBuffer pdu = OctetBuffer.allocate( payload.length + 12 ); 00162 00163 pdu.putChar( (char) ( this.sourceCallNumber | 0x8000 ) ); 00164 pdu.putChar( (char) this.destinationCallNumber ); 00165 00166 long ts = this.getTimestamp (); 00167 ts = ( (0x100000000L & ts) > 0 ) ? ts - 0x100000000L : ts; 00168 pdu.putInt( (int) ts ); 00169 00170 pdu.put( (byte) outSeqNo ); 00171 pdu.put( (byte) inSeqNo ); 00172 pdu.put( (byte) pduType ); 00173 pdu.put( (byte) pduSubclass ); 00174 00175 pdu.put( payload ); 00176 00177 log( "Sent" ); 00178 00179 this.call.send( pdu ); 00180 } 00181 00182 /** 00183 * Arrived is called when a packet arrives. This method doesn't do anything 00184 * more than dumping the frame. It should be overridden in derived class. 00185 */ 00186 void onArrivedPDU () 00187 { 00188 dump( "Inbound" ); 00189 } 00190 00191 /** 00192 * Logs the time-stamp and the inbound/outbound stream sequence number. 00193 * 00194 * @param prefix Text to include 00195 */ 00196 protected void log( String prefix ) 00197 { 00198 StringBuffer sb = new StringBuffer( "Time: " ); 00199 00200 sb.append( this.call.getTimestamp () ).append( ", " ); 00201 sb.append( prefix ); 00202 sb.append( ", Timestamp: " ).append( this.getTimestamp () ); 00203 sb.append( ", iseq: " ).append( inSeqNo ); 00204 sb.append( ", oseq: " ).append( outSeqNo ); 00205 00206 Log.debug( sb.toString () ); 00207 } 00208 00209 /** 00210 * Logs this frame. 00211 */ 00212 void dump( String prefix ) 00213 { 00214 if ( ! Log.isEnabled( Log.VERB ) ) { 00215 return; 00216 } 00217 00218 StringBuffer sb = new StringBuffer (); 00219 00220 if ( prefix != null ) { 00221 sb.append( prefix ).append( " " ); 00222 } 00223 00224 sb.append( "PDU:" ); 00225 sb.append( "\n Source Call = " ).append( sourceCallNumber ); 00226 sb.append( "\n Dest Call = " ).append( destinationCallNumber ); 00227 sb.append( "\n Timestamp = " ).append( timeStamp ); 00228 sb.append( "\n Out Seq No = " ).append( outSeqNo ); 00229 sb.append( "\n In Seq No = " ).append( inSeqNo ); 00230 sb.append( "\n PDU Type = " ).append( pduType ); 00231 sb.append( "\n Subclass = " ).append( pduSubclass ); 00232 00233 Log.verb( sb.toString () ); 00234 } 00235 } 00236