Add Registration functionality and tidy up
[WeStealzYourDataz.git] / src / uk / ac / ntu / n0521366 / wsyd / libs / net / WSYD_SocketAddress.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.net.InetAddress;
27 import java.net.InetSocketAddress;
28 import java.net.UnknownHostException;
29 import java.io.IOException;
30 import java.text.MessageFormat;
31 import uk.ac.ntu.n0521366.wsyd.libs.net.Network;
32
33
34 /**
35  * Network socket properties.
36  * 
37  * Encapsulates java.net.InetSocketAddress (which cannot be usefully overridden)
38  * and adds additional attributes for the IP protocol, multicast, and isReachable
39  * properties of a socket.
40  * 
41  * This class doesn't own or control a socket object, only the attributes needed
42  * to create the socket.
43  * 
44  * Serializable to allow passing between separate local and remote processes
45  *
46  * @author Eddie Berrisford-Lynch <dev@fun2be.me>
47  */
48 public class WSYD_SocketAddress implements java.io.Serializable {
49     Boolean _multicast;
50     Boolean _isReachable;
51     Protocol _protocol;
52     InetSocketAddress _socketAddress;
53     
54     public static enum Protocol {TCP, UDP}
55
56     public static byte[] stringIPv4ToBytes4(String ipv4) throws IllegalArgumentException {
57         byte[] result = new byte[4];
58         if (ipv4 == null)
59             throw new IllegalArgumentException("reference cannot be null");
60         
61         String[] elements = ipv4.split("\\.");
62         if (elements.length != 4)
63             throw new IllegalArgumentException(MessageFormat.format("Not a correct dotted decimal notation: {0}", ipv4));
64         
65         int i = 0;
66         for (int index = 0; index <= 3; index++) {
67             try {
68                 i = Integer.parseInt(elements[index]);
69             } catch (NumberFormatException e) {
70                 throw new IllegalArgumentException(MessageFormat.format("Not a decimal number: {0}", elements[index]));
71             }
72             if (i < 0)
73                 throw new IllegalArgumentException(MessageFormat.format("Value must not be negative: {0}", i));
74             if (i > 255)
75                 throw new IllegalArgumentException(MessageFormat.format("Value must not be greater than 255: {0}", i));
76             result[index] = (byte) i;
77         }
78         
79         return result;
80     }
81
82     /**
83      * Default constructor.
84      */
85     public WSYD_SocketAddress() {
86         _multicast = false;
87         _isReachable = false;
88         _protocol = Protocol.TCP;
89         _socketAddress = null;
90     }
91
92     /**
93      * Construct a viable Socket.
94      * 
95      * @param address host IP address
96      * @param port number
97      * @param protocol network protocol (TCP or UDP)
98      */
99     public WSYD_SocketAddress(InetAddress address, int port, Protocol protocol) {
100         this(); // call the default constructor
101         _protocol = protocol;
102         setPort(port);
103         setAddress(address); // must be done last since it calls setReachable()
104     }
105
106     /**
107      * Construct a viable TCP Socket.
108      * 
109      * TCP is selected as the default protocol.
110      * 
111      * @param address host IP address
112      * @param port number
113      */
114     public WSYD_SocketAddress(InetAddress address, int port) {
115         this(address, port, Protocol.TCP); // call primary constructor with default parameter
116     }
117     
118     /**
119      * Construct a viable TCP Socket on an ephemeral port.
120      * 
121      * TCP is selected as the default protocol. An ephemeral port is allocated
122      * by the operating system.
123      * 
124      * @param address host IP address
125      */
126     public WSYD_SocketAddress(InetAddress address) {
127         this(address, 0, Protocol.TCP);
128     }
129     
130     /**
131      * Construct a viable Socket on all interfaces.
132      *
133      * The wildcard IP address is used to listen on all available interfaces.
134      *
135      * @see java.net.ServerSocket#bind
136      * @param port number
137      * @param protocol Protocol.TCP or Protocol.UDP
138      * @throws UnknownHostException 
139      */
140     public WSYD_SocketAddress(int port, Protocol protocol) throws UnknownHostException {
141         this(Network.IPv4_WILDCARD, port, protocol);
142     }
143     
144     /**
145      * Construct a viable TCP Socket on all interfaces.
146      * 
147      * TCP is selected as the default protocol. The wildcard IP address is
148      * used.
149      * 
150      * @see java.net.ServerSocket#bind
151      * @param port number
152      * @throws UnknownHostException
153      */
154     public WSYD_SocketAddress(int port) throws UnknownHostException {
155         this(Network.IPv4_WILDCARD, port, Protocol.TCP);
156     }
157     
158     /**
159      * Set IP Address and Port.
160      * 
161      * @param address IP address
162      * @param port number
163      */
164     public void setSocketAddress(InetAddress address, int port) {
165         _socketAddress = new InetSocketAddress(address, port);
166         setMulticast();
167         setReachable();
168     }
169
170     /**
171      * Get the SocketAddress.
172      * 
173      * @return the address and port
174      */
175     public InetSocketAddress getSocketAddress() {
176         return _socketAddress;
177     }
178
179     /**
180      * Set the IP address.
181      * 
182      * Use the current port, or if no address is currently assigned, pick an ephemeral port.
183      * 
184      * @param address IP address
185      */
186     public final void setAddress(InetAddress address) {
187         // keep existing port number
188         int tempPort = (_socketAddress == null) ? 0 : _socketAddress.getPort();
189         setSocketAddress(address, tempPort);
190     }
191     
192     /**
193      * Get the Socket IP address.
194      * 
195      * @return the IP address
196      */
197     public InetAddress getAddress() {
198         return _socketAddress.getAddress();
199     }
200     
201     /**
202      * Set the Socket port.
203      * 
204      * Use the current InetAddress, or if no address is currently assigned, user the wildcard address.
205      * 
206      * @param port  0 requests an ephemeral port
207      * @throws IllegalArgumentException
208      */
209     public final void setPort(int port) throws IllegalArgumentException {
210         // keep existing InetAddress
211         InetAddress tempAddress = (_socketAddress == null) ?  Network.IPv4_WILDCARD : _socketAddress.getAddress();
212         setSocketAddress(tempAddress, port);
213     }
214     
215     /**
216      * Get the Socket port.
217      * 
218      * @return port number
219      */
220     public int getPort() {
221         return _socketAddress.getPort();
222     }
223
224     /**
225      * Set the IP protocol to use.
226      * 
227      * @param protocol Protocol.TCP or Protocol.UDP
228      */
229     public void setProtocol(Protocol protocol) {
230         _protocol = protocol;
231         setMulticast(); // if it's TCP then it can't be multicast, so update multicast flag
232     }
233     
234     /**
235      * Get the current protocol
236      * 
237      * @return Protocol.TCP or Protocol.UDP
238      */
239     public Protocol getProtocol() {
240         return _protocol;
241     }
242     
243     /**
244      * Set Multicast property if the address is <em>Organisation Local</em>.
245      * 
246      * This is valid for both IPv4 and IPv6 addresses.
247      */
248     private void setMulticast() {
249         _multicast = false; // start with the assumption this isn't multicast
250         if (_protocol == Protocol.UDP) {
251             if (_socketAddress != null) {
252                 // only use Site Local MultiCast addresses
253                 _multicast = _socketAddress.getAddress().isMCOrgLocal();
254             }
255         }
256     }
257     
258     /**
259      * Get the Multicast status of this Socket.
260      * 
261      * @return true if the address is Multicast
262      */
263     public boolean isMulticast() {
264         return _multicast;
265     }
266
267     /**
268      * Test the route to the host (but not the port) if the
269      * address isn't Multicast.
270      * 
271      * @return true if the host is reachable
272      */
273     protected boolean setReachable() {
274         if (!_multicast) {
275             try {
276                 _isReachable = _socketAddress.getAddress().isReachable(1000);
277             }
278             catch(IOException e) {
279             }
280         }        
281         return _isReachable;
282     }
283     
284     /**
285      * Get the result of the last isReachable() test but don't do a test now.
286      * 
287      * @return true if the host was reachable last time it was tested
288      */
289     public boolean getReachable() {
290         return _isReachable;
291     }
292     
293     /**
294      * Constructs a string representation of this Socket.
295      * 
296      * @return String representation of the Socket state
297      */
298     @Override
299     public final String toString() {
300         return "Address: " + _socketAddress.getAddress() + ", "
301              + "Port: " + _socketAddress.getPort() + ", "
302              + "Protocol: " + _protocol.toString() + ", "
303              + "MultiCast: " + _multicast.toString();
304     }   
305 }