📄 httpconnection.java.svn-base
字号:
/*******************************************************************************
Library of additional graphical screens for J2ME applications
Copyright (C) 2003-08 Jimm Project
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
********************************************************************************
File: src/jimm/comm/connections/HTTPConnection.java
Version: ###VERSION### Date: ###DATE###
Author(s): Andreas Rossbacher
*******************************************************************************/
package jimm.comm.connections;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import jimm.JimmException;
import jimm.Options;
import jimm.MainThread;
import jimm.comm.DisconnectPacket;
import jimm.comm.Icq;
import jimm.comm.Packet;
import jimm.comm.Util;
//#sijapp cond.if modules_TRAFFIC is "true" #
import jimm.Traffic;
//#sijapp cond.end#
public class HTTPConnection extends Connection implements Runnable
{
// Connection variables
private HttpConnection hcm; // Connection for monitor URLs (receiving)
private HttpConnection hcd; // Connection for data URLSs (sending)
private InputStream ism;
private OutputStream osd;
// URL for the monitor thread
private String monitorURL;
// HTTP Connection sequence
private int seq;
// HTTP Connection session ID
private String sid;
// IP and port of HTTP Proxy Server to connect to
private String proxy_host;
private int proxy_port;
// Counter for the connections to the http proxy server
private int connSeq;
public HTTPConnection()
{
seq = 0;
connSeq = 0;
monitorURL = "http://http.proxy.icq.com/hello";
// Set starting point for seq numbers (not bigger then 0x8000)
flapSEQ = getSeqValue();
}
// Opens a connection to the specified host and starts the receiver thread
public synchronized void connect(String hostAndPort)
throws JimmException
{
try
{
connSeq++;
// If this is the first connection initialize the connection with the proxy
if (connSeq == 1)
{
this.setInputCloseFlag(false);
this.rcvThread = new Thread(this);
this.rcvThread.start();
// Wait the the finished init will notify us
this.wait();
}
// Extract host and port from combined String (we need port as int value)
String icqserver_host = hostAndPort.substring(0, hostAndPort
.indexOf(":"));
int icqserver_port = Integer.parseInt(hostAndPort
.substring(hostAndPort.indexOf(":") + 1));
// System.out.println("Connect via "+proxy_host+":"+proxy_port+" to: "+icqserver_host+" "+icqserver_port);
// Send anser packet with connect to real server (via proxy)
byte[] packet = new byte[icqserver_host.length() + 4];
Util.putWord(packet, 0, icqserver_host.length());
System.arraycopy(Util.stringToByteArray(icqserver_host), 0,
packet, 2, icqserver_host.length());
Util.putWord(packet, 2 + icqserver_host.length(),
icqserver_port);
this.sendPacket(null, packet, 0x003, connSeq);
// If this was not the first connection to the ICQ server close the previous
if (connSeq != 1)
{
DisconnectPacket reply = new DisconnectPacket();
this.sendPacket(reply, null, 0x0005, connSeq - 1);
this.sendPacket(null, new byte[0], 0x0006, connSeq - 1);
}
} catch (IllegalArgumentException e)
{
throw (new JimmException(127, 0));
} catch (InterruptedException e)
{
// Do nothing
}
}
/*****************************************************************************
*****************************************************************************
*
* Sends and gets packets wraped in http requeste from ICQ http proxy server.
* Packets to send and receive look like this:
*
* WORD Size Size of the upcoming packet
* WORD Version Version of the ICQ Proxy Protocol (always 0x0443)
* WORD Type Type of the upcoming packet must be one of these:
* 0x0002 Reply on server hello
* 0x0003 Loginrequest to ICQ server
* 0x0004 Reply to login
* 0x0005 FLAP packet
* 0x0006 Close connection
* 0x0007 Close connection reply
* DWORD Unkn 0x00000000
* WORD Unkn 0x0000
* WORD ConnSq Number of connection the packet is for
* ... Data Data of the packet (Size - 14 bytes)
*
*****************************************************************************
*****************************************************************************/
// Sends the specific packet (with the possibility of setting the packet type
public void sendPacket(Packet packet, byte[] rawData, int type,
int connCount) throws JimmException
{
// Set the connection parameters
try
{
this.hcd = (HttpConnection) Connector.open("http://"
+ proxy_host + ":" + proxy_port + "/data?sid=" + sid
+ "&seq=" + seq, Connector.READ_WRITE);
this.hcd.setRequestProperty("User-Agent", Options
.getString(Options.OPTION_HTTP_USER_AGENT));
this.hcd.setRequestProperty("x-wap-profile", Options
.getString(Options.OPTION_HTTP_WAP_PROFILE));
this.hcd.setRequestProperty("Cache-Control",
"no-store no-cache");
this.hcd.setRequestProperty("Pragma", "no-cache");
this.hcd.setRequestMethod(HttpConnection.POST);
this.osd = this.hcd.openOutputStream();
} catch (IOException e)
{
this.notifyToDisconnect();
}
// Throw exception if output stream is not ready
if (this.osd == null)
{
throw (new JimmException(128, 0, true));
}
// Request lock on output stream
synchronized (this.osd)
{
// Send packet and count the bytes
try
{
byte[] outpack;
// Add http header (it has 14 bytes)
if (rawData == null)
{
// Set sequence numbers
packet.setSequence(getFlapSequence());
rawData = packet.toByteArray();
outpack = new byte[14 + rawData.length];
}
outpack = new byte[14 + rawData.length];
Util.putWord(outpack, 0, rawData.length + 12); // Length
Util.putWord(outpack, 2, 0x0443); // Version
Util.putWord(outpack, 4, type);
Util.putDWord(outpack, 6, 0x00000000); // Unknown
Util.putDWord(outpack, 10, connCount);
// The "real" data
System.arraycopy(rawData, 0, outpack, 14, rawData.length);
// System.out.println("Sent: "+outpack.length+" b");
this.osd.write(outpack);
// this.osd.flush();
// Send the data
if (hcd.getResponseCode() != HttpConnection.HTTP_OK)
this.notifyToDisconnect();
else
seq++;
try
{
this.osd.close();
this.hcd.close();
} catch (Exception e)
{
// Do nothing
} finally
{
this.osd = null;
this.hcd = null;
}
//#sijapp cond.if modules_TRAFFIC is "true" #
// 40 is the overhead for each packet (TCP/IP)
// 190 is the ca. overhead for the HTTP header
// 14 bytes is the overhead for ICQ HTTP data header
// 170 bytes is the ca. overhead of the HTTP/1.1 200 OK
Traffic.addOutTraffic(outpack.length + 40 + 190 + 14 + 170);
MainThread.updateContactListCaption();
//#sijapp cond.end#
} catch (IOException e)
{
this.notifyToDisconnect();
}
}
}
// Sends the specified packet always type 5 (FLAP packet)
public void sendPacket(Packet packet) throws JimmException
{
this.sendPacket(packet, null, 0x0005, connSeq);
}
// Main loop
public void run()
{
// Required variables
byte[] length = new byte[2];
byte[] httpPacket;
byte[] packet = new byte[0];
int flapMarker = 0;
int bRead, bReadSum;
int bReadSumRequest = 0;
// Reset packet buffer
synchronized (this)
{
this.rcvdPackets = new Vector();
}
// Try
try
{
// Check abort condition
while (!this.getInputCloseFlag())
{
// Set connection parameters
this.hcm = (HttpConnection) Connector.open(monitorURL,
Connector.READ_WRITE);
this.hcm.setRequestProperty("User-Agent", Options
.getString(Options.OPTION_HTTP_USER_AGENT));
this.hcm.setRequestProperty("x-wap-profile", Options
.getString(Options.OPTION_HTTP_WAP_PROFILE));
this.hcm.setRequestProperty("Cache-Control",
"no-store no-cache");
this.hcm.setRequestProperty("Pragma", "no-cache");
this.hcm.setRequestMethod(HttpConnection.GET);
this.ism = this.hcm.openInputStream();
if (hcm.getResponseCode() != HttpConnection.HTTP_OK)
throw new IOException();
// Read flap header
bReadSumRequest = 0;
do
{
bReadSum = 0;
// Read HTTP packet length information
do
{
bRead = ism.read(length, bReadSum, length.length
- bReadSum);
if (bRead == -1)
break;
bReadSum += bRead;
bReadSumRequest += bRead;
} while (bReadSum < length.length);
if (bRead == -1)
break;
// Allocate memory for packet data
httpPacket = new byte[Util.getWord(length, 0)];
bReadSum = 0;
// Read HTTP packet data
do
{
bRead = ism.read(httpPacket, bReadSum,
httpPacket.length - bReadSum);
if (bRead == -1)
break;
bReadSum += bRead;
bReadSumRequest += bRead;
} while (bReadSum < httpPacket.length);
if (bRead == -1)
break;
// Only process type 5 (flap) packets
if (Util.getWord(httpPacket, 2) == 0x0005)
{
// Packet has 12 bytes header and could contain more than one FLAP
int contBytes = 12;
while (contBytes < httpPacket.length)
{
// Verify flap header only if we are sure there is a start
if (flapMarker == 0)
{
if (Util.getByte(httpPacket, contBytes) != 0x2A)
{
throw (new JimmException(124, 0));
}
// Copy flap packet data from http packet
packet = new byte[Util.getWord(httpPacket,
contBytes + 4) + 6];
}
// Read packet data form httpPacket to packet
// Packet contains the end of the flap packet
if (httpPacket.length - contBytes >= (packet.length - flapMarker))
{
System.arraycopy(httpPacket, contBytes,
packet, flapMarker,
(packet.length - flapMarker));
contBytes += (packet.length - flapMarker);
flapMarker = packet.length;
}
// Packet does not contain the end of the flap packet
else
{
System.arraycopy(httpPacket, contBytes,
packet, flapMarker,
httpPacket.length - contBytes);
flapMarker += (httpPacket.length - contBytes);
contBytes += httpPacket.length - contBytes;
}
// If all the bytes from a flap packet have been read add that packet to the queue
if (flapMarker == packet.length)
{
// Lock object and add rcvd packet to vector
synchronized (this.rcvdPackets)
{
this.rcvdPackets.addElement(packet);
}
flapMarker = 0;
}
}
// Notify main loop
synchronized (Icq.getWaitObj())
{
Icq.getWaitObj().notify();
}
} else if (Util.getWord(httpPacket, 2) == 0x0007)
{
// Construct and handle exception if we get a close rep for the connection we are
// currently using
if (Util.getWord(httpPacket, 10) == connSeq)
throw new JimmException(221, 0);
} else if (Util.getWord(httpPacket, 2) == 0x0002)
{
synchronized (this)
{
// Init answer from proxy set sid and proxy_host and proxy_port
byte[] temp = new byte[16];
System.arraycopy(httpPacket, 10, temp, 0, 16);
sid = Util.byteArrayToHexString(temp);
// Get IP of proxy
byte[] ip = new byte[Util.getWord(httpPacket,
26)];
System.arraycopy(httpPacket, 28, ip, 0,
ip.length);
this.proxy_host = Util.byteArrayToString(ip);
// Get port for proxy
this.proxy_port = Util.getWord(httpPacket,
28 + ip.length);
// Set monitor URL to non init value
monitorURL = "http://" + proxy_host + ":"
+ proxy_port + "/monitor?sid=" + sid;
this.notify();
}
}
} while (bReadSumRequest < hcm.getLength());
//#sijapp cond.if modules_TRAFFIC is "true" #
// This is not accurate for http connection
// 42 is the overhead for each packet (2 byte packet length) (TCP IP)
// 185 is the overhead for each monitor packet HTTP HEADER
// 175 is the overhead for each HTTP/1.1 200 OK answer header
// ICQ HTTP data header is counted in bReadSum
Traffic.addInTraffic(bReadSumRequest + 42 + 185 + 175);
MainThread.updateContactListCaption();
//#sijapp cond.end#
try
{
this.ism.close();
this.hcm.close();
} catch (Exception e)
{
// Do nothing
} finally
{
this.ism = null;
this.hcm = null;
}
}
}
// Catch communication exception
catch (NullPointerException e)
{
if (!this.getInputCloseFlag())
{
// Construct and handle exception
JimmException f = new JimmException(125, 3);
JimmException.handleException(f);
} else
{ /* Do nothing */
}
}
// Catch JimmException
catch (JimmException e)
{
// Handle exception
JimmException.handleException(e);
}
// Catch IO exception
catch (IOException e)
{
if (!this.getInputCloseFlag())
{
// Construct and handle exception
JimmException f = new JimmException(125, 1);
JimmException.handleException(f);
} else
{ /* Do nothing */
}
}
closeStreams();
if (typeNetwork == JimmException.ICQ_MAIN)
Icq.setNotConnected();
}
private void closeStreams()
{
try { this.ism.close(); } catch (Exception e) {}
this.ism = null;
try { this.osd.close(); } catch (Exception e) {}
this.osd = null;
try { this.hcm.close(); } catch (Exception e) {}
this.hcm = null;
try { this.hcd.close(); } catch (Exception e) {}
this.hcd = null;
}
public void forceDisconnect()
{
setInputCloseFlag(true);
closeStreams();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -