Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
15 arune 1
/**
2
 * File created by Jimmy
3
 * at 2003-dec-28 19:56:06
4
 */
5
package Macbeth.Transports;
6
 
7
import Macbeth.Net.ServerDataHandler;
8
import Macbeth.Net.TcpClient;
9
import Macbeth.Net.TcpServer;
10
import Macbeth.Utilities.MySystem;
11
import Macbeth.System.*;
12
import java.io.IOException;
13
import java.net.UnknownHostException;
14
 
15
import org.xml.sax.SAXException;
16
 
17
/**
18
 * An internet packet delivery transport for the Macbeth kernel.
19
 * This will deliver packets to and from other remotely located
20
 * Macbeth kernels via the internet.
21
 * @author Jimmy
22
 */
23
public class MbInternetTransport extends MbPacketTransport {
24
 
25
    //A list of known kernels.
26
    public MbInternetAddressList kernelList;
27
    //The TCP port on which we're listening for internet packets.
28
    public int ourPort;
29
    //Indicates whether or not we're currently receaving a packet as a raw string on the internet server.
30
    private boolean receivingPacketString;
31
    //Indicates whether an XML declaration (eg. <?xml version="1.0" encoding="Unicode"?>) has been received
32
    private boolean xmlDeclarationReceived;
33
    private String receivedString;
34
    private String clientRemoteAddress;
35
 
36
    //our tcp server
37
    private TcpServer server;
38
    //our tcp client
39
    private TcpClient client;
40
 
41
    /**
42
     * Creates a new instance of MbInternetTransport.
43
     */
44
    public MbInternetTransport(MbKernel parentKernel) {
45
        super(parentKernel);
46
        //create new kernel list
47
        kernelList = new MbInternetAddressList();
48
        //initial values
49
        ourPort = 19000;
50
        receivingPacketString = false;
51
        xmlDeclarationReceived = false;
52
        receivedString = "";
53
        clientRemoteAddress = "";
54
        server = null;
55
        client = null;
56
    }
57
 
58
    /**
59
     * Starts up the internet delivery system.
60
     */
61
    public void startup() {
62
        super.startup();
63
        //start inet server and use our own ServerDataHandler interface to handle data
64
        server = new TcpServer(ourPort,new MyServerDataHandler());
65
        server.startServer();
66
    }
67
 
68
    /**
69
     * Shuts down the internet delivery system.
70
     */
71
    public void shutdown() {
72
        super.shutdown();
73
        //shut down internet server
74
        server.stopServer();
75
    }
76
 
77
    /**
78
     * Returns the name of this transport.
79
     * @return The name of this transport.
80
     */
81
    public String getName() {
82
        return "Internet transport";
83
    }
84
 
85
    /**
86
     * Tries to deliver a packet via the internet transport.
87
     * @param p The packet that needs to be delivered.
88
     * @return True if the packet has been delivered successfully.
89
     * False if this packet cannot be delivered via this transport
90
     * (that is, if it has a destination kernel that is either unknown
91
     * or local, "self").
92
     * @throws Macbeth.System.MbPacketTransport.MbPacketDeliveryException if an error occured while trying
93
     * to deliver the packet (I/O-errors or invalid addresses).
94
     */
95
    public boolean deliverPacket(MbPacket p) throws MbPacketTransport.MbPacketDeliveryException {
96
        MbInternetAddress kernelAddress = kernelList.getAddress(p.getDestination().getKernel());
97
        //if no such kernel existed in our kernel list...
98
        if (kernelAddress==null) {
99
            //then we cannot deliver this packet
100
            return false;
101
            //if we do know about the destination kernel
102
        } else {
103
            //lets deliver
104
            try {
105
                deliverPacketViaInternet(p,kernelAddress);
106
            } catch (Exception e) {
107
                throw new MbPacketTransport.MbPacketDeliveryException(e.toString());
108
            }
109
        }
110
        return true;
111
    }
112
 
113
    /**
114
     * Delivers a packet via internet.
115
     * @param p The packet that should be delivered.
116
     * @param addr The kernel address to which the packet should be delivered.
117
     * @throws IOException if an I/O-error occurs while trying to send the packet.
118
     * @throws UnknownHostException if the specified address is invalid.
119
     */
120
    protected void deliverPacketViaInternet(MbPacket p, MbInternetAddress addr)
121
            throws IOException, UnknownHostException
122
    {
123
        //connect our TCP client to the specified host and port
124
        client = new TcpClient(addr.getPort(),addr.getHostname());
125
        client.openConnection();
126
        //send the packet via the client
127
        client.sendString(p.serializeToString());
128
        //and then disconnect
129
        client.closeConnection();
130
        client = null;
131
        //we've now sent the packet successfully, so increase sent packets-counter
132
        packetsSent++;
133
    }
134
 
135
 
136
    /**
137
     * Will take care of incoming server data.
138
     */
139
    private class MyServerDataHandler implements ServerDataHandler {
140
        /**
141
         * Will be called when server has received a string
142
         * that your datahandler need to take care of.
143
         * @param data The received string.
144
         */
145
        public void handleServerData(String data, String address) {
146
            //does the string contain an XML declaration line?
147
            int xmlDeclarationStart = data.indexOf("<?xml");
148
            if (xmlDeclarationStart!=-1) {
149
                //if so, start receiving the (new) XML document (discarding any previously received data)
150
                receivedString = data.substring(xmlDeclarationStart) + MySystem.lineBreak;
151
                xmlDeclarationReceived = true;
152
            }
153
            //does the string contain the root element of a macbeth packet?
154
            int mbpacketStart = data.indexOf("<mbpacket");
155
            if (mbpacketStart != -1) {
156
                //If so, we're about to begin receiving a packet, but first we must make sure that
157
                //the XML document contains an XML declaration. If this has not already been received...
158
                if (!xmlDeclarationReceived) {
159
                    //begin with a standard declaration (assume ascii!)
160
                    receivedString = "<?xml version=\"1.0\" encoding=\"ascii\"?>" + MySystem.lineBreak;
161
                    //and add everything after the root element
162
                    receivedString += data.substring(mbpacketStart);
163
                }
164
                //the XML declaration HAS been received
165
                else {
166
                    //just append the data to the existing string
167
                    receivedString += data;
168
                }
169
                receivingPacketString = true;
170
                //also put the clients remote address into this packet
171
                receivedString += MySystem.lineBreak + "<remoteaddress value=\"" + clientRemoteAddress + "\"/>" + MySystem.lineBreak;
172
            }
173
            //does this line close the root element of a macbeth packet?
174
            int mbpacketEnd = data.indexOf("</mbpacket>");
175
            if (mbpacketEnd != -1 && receivingPacketString) {
176
                receivedString += data.substring(0, mbpacketEnd + "</mbpacket>".length());
177
                MbPacket p = new MbPacket();
178
                //if so, try to create a packet from the string we've received
179
                try {
180
                    p.createFromString(receivedString);
181
                    //if successful, handle this packet now
182
                    packetReceived(p);
183
                }
184
                catch (SAXException e) {
185
                    //if unsuccessful, log this error
186
                    _info.println("A string was received on the server port, but it could not " +
187
                                  "be identified as a packet due to syntax errors (" + e + ")");
188
                    _info.println("The received string was:" + MySystem.lineBreak + receivedString);
189
                }
190
                //clear received-string now
191
                receivedString = new String();
192
                xmlDeclarationReceived = false;
193
            }
194
            //all data inside the packet should just be appended
195
            if (mbpacketStart==-1 && mbpacketEnd==-1 && xmlDeclarationStart==-1 && receivingPacketString) {
196
                receivedString += data;
197
            }
198
        }
199
 
200
        /**
201
         * Notifies your datahandler about a clients remote address.
202
         * Will be called by server when a new socket is opened.
203
         * @param address The clients remote address (IP number)
204
         */
205
        public void setRemoteAddress(String address) {
206
            //save the remote address for later use
207
            clientRemoteAddress = address;
208
        }
209
 
210
        public void clientDropped(String address) { }
211
    }
212
}