4 * Copyright 2015 Eddie Berrisford-Lynch <dev@fun2be.me>.
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 package uk.ac.ntu.n0521366.wsyd.libs.net;
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;
35 * Network socket properties.
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.
41 * This class doesn't own or control a socket object, only the attributes needed
42 * to create the socket.
44 * Serializable to allow passing between separate local and remote processes
46 * @author Eddie Berrisford-Lynch <dev@fun2be.me>
48 public class WSYD_SocketAddress implements java.io.Serializable {
52 InetSocketAddress _socketAddress;
54 public static enum Protocol {TCP, UDP}
56 public static byte[] stringIPv4ToBytes4(String ipv4) throws IllegalArgumentException {
57 byte[] result = new byte[4];
59 throw new IllegalArgumentException("reference cannot be null");
61 String[] elements = ipv4.split("\\.");
62 if (elements.length != 4)
63 throw new IllegalArgumentException(MessageFormat.format("Not a correct dotted decimal notation: {0}", ipv4));
66 for (int index = 0; index <= 3; index++) {
68 i = Integer.parseInt(elements[index]);
69 } catch (NumberFormatException e) {
70 throw new IllegalArgumentException(MessageFormat.format("Not a decimal number: {0}", elements[index]));
73 throw new IllegalArgumentException(MessageFormat.format("Value must not be negative: {0}", i));
75 throw new IllegalArgumentException(MessageFormat.format("Value must not be greater than 255: {0}", i));
76 result[index] = (byte) i;
83 * Default constructor.
85 public WSYD_SocketAddress() {
88 _protocol = Protocol.TCP;
89 _socketAddress = null;
93 * Construct a viable Socket.
95 * @param address host IP address
97 * @param protocol network protocol (TCP or UDP)
99 public WSYD_SocketAddress(InetAddress address, int port, Protocol protocol) {
100 this(); // call the default constructor
101 _protocol = protocol;
103 setAddress(address); // must be done last since it calls setReachable()
107 * Construct a viable TCP Socket.
109 * TCP is selected as the default protocol.
111 * @param address host IP address
114 public WSYD_SocketAddress(InetAddress address, int port) {
115 this(address, port, Protocol.TCP); // call primary constructor with default parameter
119 * Construct a viable TCP Socket on an ephemeral port.
121 * TCP is selected as the default protocol. An ephemeral port is allocated
122 * by the operating system.
124 * @param address host IP address
126 public WSYD_SocketAddress(InetAddress address) {
127 this(address, 0, Protocol.TCP);
131 * Construct a viable Socket on all interfaces.
133 * The wildcard IP address is used to listen on all available interfaces.
135 * @see java.net.ServerSocket#bind
137 * @param protocol Protocol.TCP or Protocol.UDP
138 * @throws UnknownHostException
140 public WSYD_SocketAddress(int port, Protocol protocol) throws UnknownHostException {
141 this(Network.IPv4_WILDCARD, port, protocol);
145 * Construct a viable TCP Socket on all interfaces.
147 * TCP is selected as the default protocol. The wildcard IP address is
150 * @see java.net.ServerSocket#bind
152 * @throws UnknownHostException
154 public WSYD_SocketAddress(int port) throws UnknownHostException {
155 this(Network.IPv4_WILDCARD, port, Protocol.TCP);
159 * Set IP Address and Port.
161 * @param address IP address
164 public void setSocketAddress(InetAddress address, int port) {
165 _socketAddress = new InetSocketAddress(address, port);
171 * Get the SocketAddress.
173 * @return the address and port
175 public InetSocketAddress getSocketAddress() {
176 return _socketAddress;
180 * Set the IP address.
182 * Use the current port, or if no address is currently assigned, pick an ephemeral port.
184 * @param address IP address
186 public final void setAddress(InetAddress address) {
187 // keep existing port number
188 int tempPort = (_socketAddress == null) ? 0 : _socketAddress.getPort();
189 setSocketAddress(address, tempPort);
193 * Get the Socket IP address.
195 * @return the IP address
197 public InetAddress getAddress() {
198 return _socketAddress.getAddress();
202 * Set the Socket port.
204 * Use the current InetAddress, or if no address is currently assigned, user the wildcard address.
206 * @param port 0 requests an ephemeral port
207 * @throws IllegalArgumentException
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);
216 * Get the Socket port.
218 * @return port number
220 public int getPort() {
221 return _socketAddress.getPort();
225 * Set the IP protocol to use.
227 * @param protocol Protocol.TCP or Protocol.UDP
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
235 * Get the current protocol
237 * @return Protocol.TCP or Protocol.UDP
239 public Protocol getProtocol() {
244 * Set Multicast property if the address is <em>Organisation Local</em>.
246 * This is valid for both IPv4 and IPv6 addresses.
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();
259 * Get the Multicast status of this Socket.
261 * @return true if the address is Multicast
263 public boolean isMulticast() {
268 * Test the route to the host (but not the port) if the
269 * address isn't Multicast.
271 * @return true if the host is reachable
273 protected boolean setReachable() {
276 _isReachable = _socketAddress.getAddress().isReachable(1000);
278 catch(IOException e) {
285 * Get the result of the last isReachable() test but don't do a test now.
287 * @return true if the host was reachable last time it was tested
289 public boolean getReachable() {
294 * Constructs a string representation of this Socket.
296 * @return String representation of the Socket state
299 public final String toString() {
300 return "Address: " + _socketAddress.getAddress() + ", "
301 + "Port: " + _socketAddress.getPort() + ", "
302 + "Protocol: " + _protocol.toString() + ", "
303 + "MultiCast: " + _multicast.toString();