Add Registration functionality and tidy up
[WeStealzYourDataz.git] / src / uk / ac / ntu / n0521366 / wsyd / libs / net / NetworkServerTCP.java
1 /*
2  * The MIT License
3  *
4  * Copyright 2015 Eddie Berrisford-Lynch <dev@fun2be.me>.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 package uk.ac.ntu.n0521366.wsyd.libs.net;
25
26 import java.io.IOException;
27 import java.net.InetSocketAddress;
28 import java.net.ServerSocket;
29 import java.net.Socket;
30 import java.net.SocketException;
31 import java.net.SocketTimeoutException;
32 import java.text.MessageFormat;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
37 import uk.ac.ntu.n0521366.wsyd.libs.message.MessageNetworkStream;
38
39 /**
40  * Dual-use multithreading network TCP server that can be used stand-alone
41  * or in a Swing GUI application as a background worker thread.
42  *
43  * @see NetworkServerAbstract
44  * @author Eddie Berrisford-Lynch <dev@fun2be.me>
45  */
46 public class NetworkServerTCP extends NetworkServerAbstract {
47     
48     ServerSocket _serverSocket;
49     
50     NetworkStreamManager _streamManager;
51     
52     protected ArrayList<ConnectionEstablishedEventListener> _ConnectionEstablishedEventListeners;
53
54      /**
55      * Construct the server with a Logger.
56      * 
57      * No socket is opened.
58      * 
59      * @param socketAddress The socket to listen on
60      * @param title source identifier for use in log messages and sent NetworkMessage objects
61      * @param serviceToHostMap the map object used for host <> InetSocketAddress lookups
62      * @param manager
63      * @param logger An instance of Logger to be used by all objects of this class
64      */
65     public NetworkServerTCP(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap, NetworkStreamManager manager, Logger logger) {
66         super(socketAddress, title, serviceToHostMap, logger);
67         this._streamManager = manager;
68         this._ConnectionEstablishedEventListeners = new ArrayList<>();
69     }
70
71     /**
72      * Construct the server without a Logger.
73      * 
74      * No socket is opened.
75      * 
76      * @param socketAddress The socket to listen on
77      * @param title source identifier for use in log messages and sent NetworkMessage objects
78      * @param serviceToHostMap the map object used for host <> InetSocketAddress lookups
79      * @param manager
80      */
81     public NetworkServerTCP(WSYD_SocketAddress socketAddress, String title, ServiceAddressMap serviceToHostMap, NetworkStreamManager manager) {
82         super(socketAddress, title, serviceToHostMap);
83         this._streamManager = manager;
84     }
85     
86     /**
87      * Open the socket ready for accepting connections.
88      * 
89      * It should also set a reasonable socket timeout with a call to setSoTimeout()
90      * 
91      * @throws SocketException 
92      */
93     @Override
94     public  void serverOpen() throws SocketException {
95         try {
96             _serverSocket = new ServerSocket(_socketAddress.getPort(), 50, _socketAddress.getAddress());
97         } catch (IOException ex) {
98             throw new SocketException(ex.getMessage());
99         }
100         _serverSocket.setSoTimeout(100);
101         
102         if (_socketAddress.getPort() == Network.PORTS_EPHEMERAL) {
103             // reflect the actual port in use if an ephermal port was requested
104             InetSocketAddress actualSA = (InetSocketAddress)_serverSocket.getLocalSocketAddress();
105             _socketAddress.setAddress(actualSA.getAddress());
106             _socketAddress.setPort(actualSA.getPort());
107         }
108         //log(Level.FINEST, _title, MessageFormat.format("Connection from {0}:{1}", _socketAddress.getAddress().getCanonicalHostName(), Integer.toString(_socketAddress.getPort())));
109         // TODO: Complete this implementation
110     }
111     
112     /**
113      * Send an unsolicited message to a remote service.
114      * 
115      * This method is called by the main worker loop if there is a message to
116      * be sent.
117      * 
118      * @param message must have its _serviceTarget parameter set
119      * @return true if the message was sent
120      */
121     @Override
122     protected boolean serverSend(NetworkMessage message) {
123         boolean result = false;
124         
125         return result;
126     }
127
128     /**
129      * Close the socket.
130      * 
131      * @throws SocketException
132      */
133     @Override
134     public void serverClose() throws SocketException {
135         if (this._serverSocket != null)
136             try {
137                 this._serverSocket.close();
138         } catch (IOException ex) {
139             throw new SocketException(ex.getMessage());
140         }
141     }
142     
143     /**
144      * Accept connection from remote hosts.
145      * 
146      * This method should wait for a single incoming connection.
147      * 
148      * @return true if the server should continue listening
149      */
150     @Override
151     public boolean serverListen() {
152         boolean result = false;
153         
154         try {
155             //System.err.println("Before");
156             Socket connectionSocket = _serverSocket.accept();
157             NetworkStream newStream = new NetworkStream(connectionSocket, _streamManager);
158             long userID = _streamManager.addStream(0, newStream);
159             // workaround to enable firing a ConnectionEstablishedEvent in process() on the owner thread
160             NetworkMessage temp = new NetworkMessage("triggerConnectionEstablishedEvent", null, new MessageNetworkStream(newStream));
161             publish(temp);
162             log(Level.INFO, _title, MessageFormat.format("Incoming connection from {0}:{1}", connectionSocket.getInetAddress().getCanonicalHostName(), Integer.toString(connectionSocket.getPort())));
163             
164             // add or update the last-seen time of the Sender host in the known services map
165             ServiceAddressMap.LastSeenHost host = new ServiceAddressMap.LastSeenHost((InetSocketAddress)connectionSocket.getRemoteSocketAddress());
166             this._serviceToHostMap.put(Long.toString(userID), host);
167             log(Level.INFO, _title, MessageFormat.format("Added \"{0}\" to service map", userID));
168             System.err.println("Added new TCP stream successfully");
169         }
170         catch (SocketTimeoutException e) {
171             //Nothing to be done
172         }
173         catch (IOException e) {
174             // Nothing to be done
175             System.err.println("Incoming connection caused exception...");
176         }
177        
178         return false;
179     }
180
181     private void fireConnectionEstablishedEvent(NetworkStream stream) {
182         ConnectionEstablishedEvent event = new ConnectionEstablishedEvent(this, stream);
183         for (ConnectionEstablishedEventListener listener: this._ConnectionEstablishedEventListeners) {
184             listener.connectionEstablished(event);
185         }
186         
187     }
188     public synchronized void addConnectionEstablisedEventListener(ConnectionEstablishedEventListener listener) {
189         _ConnectionEstablishedEventListeners.add(listener);
190     }
191     
192     public synchronized void removeConnectionEstablishedEventListener(ConnectionEstablishedEventListener listener) {
193         for (ConnectionEstablishedEventListener el : _ConnectionEstablishedEventListeners)
194             if (el == listener) {
195                 _ConnectionEstablishedEventListeners.remove(listener);
196                 break;
197             }
198     }
199     
200     
201     /* XXX: Methods below here all execute on the GUI Event Dispatch Thread */
202     
203     /**
204      * Clean up after doInBackground() has returned.
205      * 
206      * This method will run on the GUI Event Dispatch Thread so must complete quickly.
207      */
208     @Override
209     protected  void done() {
210         
211     }
212
213     @Override
214     protected NetworkMessage sendMessage() {
215         return null;
216     }
217     
218     @Override
219     protected void process(List<NetworkMessage> list) {
220         System.err.println("process()");
221         for (NetworkMessage nm: list) {
222             MessageNetworkStream message = (MessageNetworkStream)nm.getMessage();
223             System.err.println("ConnectionEstablished dispatched for " + message._stream._key);
224             fireConnectionEstablishedEvent(message._stream);
225
226         }
227     }
228 }