/* / Copyright (C) 2009 Risto Känsäkoski - Sesca ISW Ltd / / This file is part of SIP-Applet (www.sesca.com, www.purplescout.com) / This file is modified from MjSip (http://www.mjsip.org) / / This program is free software; you can redistribute it and/or / modify it under the terms of the GNU General Public License / as published by the Free Software Foundation; either version 2 / of the License, or (at your option) any later version. / / This program is distributed in the hope that it will be useful, / but WITHOUT ANY WARRANTY; without even the implied warranty of / MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the / GNU General Public License for more details. / / You should have received a copy of the GNU General Public License / along with this program; if not, write to the Free Software / Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.sesca.voip.transport; import java.io.IOException; import java.nio.channels.SocketChannel; import local.net.RtpPacket; import org.zoolu.net.IpAddress; import org.zoolu.sip.message.Message; import org.zoolu.sip.provider.*; import com.sesca.audio.TunnelSenderReceiver; import com.sesca.misc.Logger; import com.sesca.voip.media.RtpHttpBridge; public class HttpTunnelTransport implements ConnectedTransport, HttpTunnelConnectionListener { /** Protocol type */ byte[] leftOvers = null; public static final String PROTO_TCP = "tcp"; /** TCP connection */ protected HttpTunnelConnection tcp_conn; private int numberOfLeftOveringOccured; /** TCP connection */ protected ConnectionIdentifier connection_id; /** The last time that has been used (in milliseconds) */ protected long last_time; /** the current received text. */ protected String text; /** Transport listener */ protected TransportListener listener; /** Creates a new TcpTransport */ public HttpTunnelTransport(IpAddress remote_ipaddr, int remote_port, TransportListener listener) throws IOException { SocketChannel audiochannel = null; if(listener instanceof RtpHttpBridge) { RtpHttpBridge laalaa = (RtpHttpBridge) listener; audiochannel = laalaa.audiochannel; } // audiosocket="+audiosocket); this.listener = listener; HttpTunnelSocket socket = null; if(audiochannel == null) { socket = new HttpTunnelSocket(remote_ipaddr, remote_port); Logger.debug("audiosocket=null"); } else { socket = new HttpTunnelSocket(audiochannel); Logger.debug("audiosocket!=null"); } tcp_conn = new HttpTunnelConnection(socket, this); connection_id = new ConnectionIdentifier(this); last_time = System.currentTimeMillis(); text = ""; } /** Costructs a new TcpTransport */ public HttpTunnelTransport(HttpTunnelSocket socket, TransportListener listener) { this.listener = listener; tcp_conn = new HttpTunnelConnection(socket, this); connection_id = null; last_time = System.currentTimeMillis(); text = ""; } /** Stops running */ public void halt() { if(tcp_conn != null) tcp_conn.halt(); } /** Gets protocol type */ public String getProtocol() { return PROTO_TCP; } public void sendMessage(Message msg, IpAddress dest_ipaddr, int dest_port) throws IOException { sendMessage(msg); } /** Sends a Message */ public void sendMessage(Message msg) throws IOException { if(tcp_conn != null) { last_time = System.currentTimeMillis(); Logger.paranoia("Lähtevä viesti:"); Logger.paranoia(msg.toString()); byte[] data = msg.toString().getBytes(); char[] message = msg.toString().toCharArray(); for (int i = 0; i < message.length; i++) { int value = message[i]; value = value & 0xFF; byte bvalue = (byte) value; data[i] = bvalue; } int length = data.length; String hexa = ""; byte[] binary = new byte[4]; binary[3] = (byte) ((length >>> 24) & 0xFF); binary[2] = (byte) ((length >>> 16) & 0xFF); binary[1] = (byte) ((length >>> 8) & 0xFF); binary[0] = (byte) ((length >>> 0) & 0xFF); String header = ""; // String header="GET / HTTP/1.1\r\n"; // header+="Ass-hole: "+(data.length+binary.length)+"\r\n"; byte[] len = header.getBytes(); byte[] packet = new byte[length + len.length + binary.length]; for (int i = 0; i < len.length; i++) { packet[i] = len[i]; } for (int i = 0; i < binary.length; i++) { packet[i + len.length] = binary[i]; } for (int i = 0; i < length; i++) { packet[i + len.length + binary.length] = data[i]; } /* * * packet=new byte[260]; packet[0]=-128; packet[1]=1; packet[2]=1; * packet[3]=1; for (int i=0;i<256;i++) { packet[i+4]=(byte)i; * * } */ // System.exit(0); // socket flush tcp_conn.send(packet, 2); // tcp_conn.send(len); // tcp_conn.send(data); } } public int getRemotePort() { if(tcp_conn != null) return tcp_conn.getRemotePort(); else return 0; } /** Gets the last time the Connection has been used (in millisconds) */ public long getLastTimeMillis() { return last_time; } /** Gets the remote IpAddress */ public IpAddress getRemoteAddress() { if(tcp_conn != null) return tcp_conn.getRemoteAddress(); else return null; } /** Gets a String representation of the Object */ public String toString() { if(tcp_conn != null) return tcp_conn.toString(); else return null; } public void onReceivedData(HttpTunnelConnection tcp_conn, byte[] data, int len) { // Logger.debug("HttpTunnelTransport.onReceivedData"); // awakes: onReceivedData"); last_time = System.currentTimeMillis(); if(listener instanceof RtpHttpBridge || listener instanceof TunnelSenderReceiver) { // Logger.debug("Transport listener = RtpHttpBridge || // TunnelSenderReceiver"); if(leftOvers != null) { numberOfLeftOveringOccured++; Logger.debug("We have leftovers (" + numberOfLeftOveringOccured + " times)"); // vajaan paketin osat"); byte[] temp = new byte[len + leftOvers.length]; for (int i = 0; i < leftOvers.length; i++) { temp[i] = leftOvers[i]; } for (int i = 0; i < len; i++) { temp[leftOvers.length + i] = data[i]; } data = new byte[temp.length]; for (int i = 0; i < temp.length; i++) { data[i] = temp[i]; } temp = null; leftOvers = null; len = data.length; } int l = len; int y = data[0] & 0xFF; int cLen = (data[0] & 0xFF) + 0x100 * (data[1] & 0xFF) + 0x10000 * (data[2] & 0xFF) + 0x1000000 * (data[3] & 0xFF); // "+data[2]+" "+data[3]+") => "+cLen); int p = 0; while (cLen < l) { // "+data[p+1]+" "+data[p+2]+" "+data[p+3]+") => "+cLen); byte[] rtp = new byte[cLen]; for (int i = 0; i < cLen; i++) { rtp[i] = data[p + i + 4]; } RtpPacket packet = new RtpPacket(rtp); // packet.setContent(rtp, rtp.length); if(listener != null) { // Logger.debug("Invoking listener ("+listener+")"); listener.onReceivedMessage(packet); } // else Logger.warning("HttpTunnelTransport: listener==null"); p = p + cLen + 4; l = l - cLen - 4; if(p + 4 <= len) // paketti ei ole lopussa, seuraavan koko voidaan // lukea { cLen = (data[p] & 0xFF) + 0x100 * (data[p + 1] & 0xFF) + 0x10000 * (data[p + 2] & 0xFF) + 0x1000000 * (data[p + 3] & 0xFF); } else if(p == len) cLen = 0; // paketti lopussa, ei jakojäännöksiä else cLen = l + 1; // paketti on lopussa, jakokohta sattui // kokoinfromaation kohdalle } if(cLen > l) { leftOvers = new byte[l]; for (int i = 0; i < l; i++) { leftOvers[i] = data[i + p]; } } // else System.err.println("RTP packet discarded: len="+len+", // calculated len="+cLen); // leftOvers not null } else { // Logger.debug("Transport listener = "+listener.getClass().getName()); // Logger.debug("Raw data:"); // Logger.debug("---- BEGINNING OF RAW DATA ----"); // Logger.debug(new String(data,0,len)); // Logger.debug("---- END OF RAW DATA ----"); // text+=new String(data,0,len); text += new String(data, 4, len - 4); // for (int i=0; i<text.length();i++) // { // } while (text.length() > 0 && text.charAt(0) == 0) { text = new String(text.substring(4)); // Logger.debug("Removed 4 characters from beginning of message"); } Logger.debug("Sending message to sip stack's message parser"); Logger.debug("Message="+text); SipParser par = new SipParser(text); Message msg = par.getSipMessage(); while (msg != null) { // Logger.debug("In a suspicious WHILE LOOP now"); msg.setRemoteAddress(tcp_conn.getRemoteAddress().toString()); msg.setRemotePort(tcp_conn.getRemotePort()); msg.setTransport(PROTO_TCP); msg.setConnectionId(connection_id); Logger.hysteria("Saapuva viesti:"); Logger.hysteria(msg.toString()); if(listener != null) { listener.onReceivedMessage(this, msg); } text = par.getRemainingString(); if(text.length() >= 4) text = text.substring(4, text.length()); par = new SipParser(text); msg = par.getSipMessage(); } } } public void onConnectionTerminated(HttpTunnelConnection tcp_conn, Exception error) { Logger.info("HttpTunnelConnectionListener(HttpTunnelTransport) awakes: onConnectionTerminated"); if(listener != null) listener.onTransportTerminated(this, error); HttpTunnelSocket socket = tcp_conn.getSocket(); if(socket != null) try { socket.close(); } catch (Exception e) {} this.tcp_conn = null; this.listener = null; } public void sendMessage(byte[] bytes, boolean flush) throws IOException { // Logger.debug("HttpTunnelTransport.sendMessage()"); if(tcp_conn != null) { last_time = System.currentTimeMillis(); int length = bytes.length; byte[] bytes2 = new byte[4 + bytes.length]; bytes2[3] = (byte) ((length >>> 24) & 0xFF); bytes2[2] = (byte) ((length >>> 16) & 0xFF); bytes2[1] = (byte) ((length >>> 8) & 0xFF); bytes2[0] = (byte) ((length >>> 0) & 0xFF); for (int i = 0; i < bytes.length; i++) { bytes2[i + 4] = bytes[i]; } // socket flush tcp_conn.send(bytes2, 1); } else Logger.warning("TCP connection==null"); } public void sendMessage(byte[] bytes, byte[] bytesB, boolean flush) throws IOException { if(tcp_conn != null) { last_time = System.currentTimeMillis(); int length = bytes.length; byte[] bytes2 = new byte[4 + bytes.length]; bytes2[3] = (byte) ((length >>> 24) & 0xFF); bytes2[2] = (byte) ((length >>> 16) & 0xFF); bytes2[1] = (byte) ((length >>> 8) & 0xFF); bytes2[0] = (byte) ((length >>> 0) & 0xFF); for (int i = 0; i < bytes.length; i++) { bytes2[i + 4] = bytes[i]; } int lengthB = bytes.length; byte[] bytes2B = new byte[4 + bytesB.length]; bytes2B[3] = (byte) ((lengthB >>> 24) & 0xFF); bytes2B[2] = (byte) ((lengthB >>> 16) & 0xFF); bytes2B[1] = (byte) ((lengthB >>> 8) & 0xFF); bytes2B[0] = (byte) ((lengthB >>> 0) & 0xFF); for (int i = 0; i < bytesB.length; i++) { bytes2B[i + 4] = bytesB[i]; } byte[] bytesToSend = new byte[bytes2.length + bytes2B.length]; for (int i = 0; i < bytes2.length; i++) { bytesToSend[i] = bytes2[i]; } for (int i = 0; i < bytes2B.length; i++) { bytesToSend[i + bytes2.length] = bytes2B[i]; } // Socket flush tcp_conn.send(bytesToSend, 1); } } public void sendBlock(byte[] bytes) throws IOException { if(tcp_conn != null) { last_time = System.currentTimeMillis(); // socket flush tcp_conn.send(bytes, 1); } } }