1 /* 2 * %CopyrightBegin% 3 * 4 * Copyright Ericsson AB 2000-2016. All Rights Reserved. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * %CopyrightEnd% 19 */ 20 package com.ericsson.otp.erlang; 21 22 import java.io.IOException; 23 import java.net.UnknownHostException; 24 25 /** 26 * Represents an OTP node. It is used to connect to remote nodes or accept 27 * incoming connections from remote nodes. 28 * 29 * <p> 30 * When the Java node will be connecting to a remote Erlang, Java or C node, it 31 * must first identify itself as a node by creating an instance of this class, 32 * after which it may connect to the remote node. 33 * 34 * <p> 35 * When you create an instance of this class, it will bind a socket to a port so 36 * that incoming connections can be accepted. However the port number will not 37 * be made available to other nodes wishing to connect until you explicitely 38 * register with the port mapper daemon by calling {@link #publishPort()}. 39 * </p> 40 * 41 * <pre> 42 * OtpSelf self = new OtpSelf("client", "authcookie"); // identify self 43 * OtpPeer other = new OtpPeer("server"); // identify peer 44 * 45 * OtpConnection conn = self.connect(other); // connect to peer 46 * </pre> 47 * 48 */ 49 public class OtpSelf extends OtpLocalNode { 50 private final OtpServerTransport sock; 51 private final OtpErlangPid pid; 52 53 /** 54 * <p> 55 * Create a self node using the default cookie. The default cookie is found 56 * by reading the first line of the .erlang.cookie file in the user's home 57 * directory. The home directory is obtained from the System property 58 * "user.home". 59 * </p> 60 * 61 * <p> 62 * If the file does not exist, an empty string is used. This method makes no 63 * attempt to create the file. 64 * </p> 65 * 66 * @param node 67 * the name of this node. 68 * 69 * @exception IOException 70 * in case of server transport failure 71 * 72 */ OtpSelf(final String node)73 public OtpSelf(final String node) throws IOException { 74 this(node, defaultCookie, 0); 75 } 76 77 /** 78 * <p> 79 * Create a self node using the default cookie and custom transport factory. 80 * The default cookie is found by reading the first line of the 81 * .erlang.cookie file in the user's home directory. The home directory is 82 * obtained from the System property "user.home". 83 * </p> 84 * 85 * <p> 86 * If the file does not exist, an empty string is used. This method makes no 87 * attempt to create the file. 88 * </p> 89 * 90 * @param node 91 * the name of this node. 92 * 93 * @param transportFactory 94 * the transport factory to use when creating connections. 95 * 96 * @exception IOException 97 * in case of server transport failure 98 * 99 */ OtpSelf(final String node, final OtpTransportFactory transportFactory)100 public OtpSelf(final String node, 101 final OtpTransportFactory transportFactory) throws IOException { 102 this(node, defaultCookie, 0, transportFactory); 103 } 104 105 /** 106 * Create a self node. 107 * 108 * @param node 109 * the name of this node. 110 * 111 * @param cookie 112 * the authorization cookie that will be used by this node when 113 * it communicates with other nodes. 114 * 115 * @exception IOException 116 * in case of server transport failure 117 */ OtpSelf(final String node, final String cookie)118 public OtpSelf(final String node, final String cookie) throws IOException { 119 this(node, cookie, 0); 120 } 121 122 /** 123 * Create a self node. 124 * 125 * @param node 126 * the name of this node. 127 * 128 * @param cookie 129 * the authorization cookie that will be used by this node when 130 * it communicates with other nodes. 131 * 132 * @param transportFactory 133 * the transport factory to use when creating connections. 134 * 135 * @exception IOException 136 * in case of server transport failure 137 */ OtpSelf(final String node, final String cookie, final OtpTransportFactory transportFactory)138 public OtpSelf(final String node, final String cookie, 139 final OtpTransportFactory transportFactory) throws IOException { 140 this(node, cookie, 0, transportFactory); 141 } 142 143 /** 144 * Create a self node. 145 * 146 * @param node 147 * the name of this node. 148 * 149 * @param cookie 150 * the authorization cookie that will be used by this node when 151 * it communicates with other nodes. 152 * 153 * @param port 154 * the port number you wish to use for incoming connections. 155 * Specifying 0 lets the system choose an available port. 156 * 157 * @exception IOException 158 * in case of server transport failure 159 */ OtpSelf(final String node, final String cookie, final int port)160 public OtpSelf(final String node, final String cookie, final int port) 161 throws IOException { 162 super(node, cookie); 163 164 sock = createServerTransport(port); 165 166 if (port != 0) { 167 this.port = port; 168 } else { 169 this.port = sock.getLocalPort(); 170 } 171 172 pid = createPid(); 173 } 174 175 /** 176 * Create a self node. 177 * 178 * @param node 179 * the name of this node. 180 * 181 * @param cookie 182 * the authorization cookie that will be used by this node when 183 * it communicates with other nodes. 184 * 185 * @param port 186 * the port number you wish to use for incoming connections. 187 * Specifying 0 lets the system choose an available port. 188 * 189 * @param transportFactory 190 * the transport factory to use when creating connections. 191 * 192 * @exception IOException 193 * in case of server transport failure 194 */ OtpSelf(final String node, final String cookie, final int port, final OtpTransportFactory transportFactory)195 public OtpSelf(final String node, final String cookie, final int port, 196 final OtpTransportFactory transportFactory) throws IOException { 197 super(node, cookie, transportFactory); 198 199 sock = createServerTransport(port); 200 201 if (port != 0) { 202 this.port = port; 203 } else { 204 this.port = sock.getLocalPort(); 205 } 206 207 pid = createPid(); 208 } 209 210 /** 211 * Get the Erlang PID that will be used as the sender id in all "anonymous" 212 * messages sent by this node. Anonymous messages are those sent via send 213 * methods in {@link OtpConnection OtpConnection} that do not specify a 214 * sender. 215 * 216 * @return the Erlang PID that will be used as the sender id in all 217 * anonymous messages sent by this node. 218 */ pid()219 public OtpErlangPid pid() { 220 return pid; 221 } 222 223 /** 224 * Make public the information needed by remote nodes that may wish to 225 * connect to this one. This method establishes a connection to the Erlang 226 * port mapper (Epmd) and registers the server node's name and port so that 227 * remote nodes are able to connect. 228 * 229 * <p> 230 * This method will fail if an Epmd process is not running on the localhost. 231 * See the Erlang documentation for information about starting Epmd. 232 * 233 * <p> 234 * Note that once this method has been called, the node is expected to be 235 * available to accept incoming connections. For that reason you should make 236 * sure that you call {@link #accept()} shortly after calling 237 * {@link #publishPort()}. When you no longer intend to accept connections 238 * you should call {@link #unPublishPort()}. 239 * 240 * @return true if the operation was successful, false if the node was 241 * already registered. 242 * 243 * @exception java.io.IOException 244 * if the port mapper could not be contacted. 245 */ publishPort()246 public boolean publishPort() throws IOException { 247 if (getEpmd() != null) { 248 return false; // already published 249 } 250 251 OtpEpmd.publishPort(this); 252 return getEpmd() != null; 253 } 254 255 /** 256 * Unregister the server node's name and port number from the Erlang port 257 * mapper, thus preventing any new connections from remote nodes. 258 */ unPublishPort()259 public void unPublishPort() { 260 // unregister with epmd 261 OtpEpmd.unPublishPort(this); 262 263 // close the local descriptor (if we have one) 264 try { 265 if (super.epmd != null) { 266 super.epmd.close(); 267 } 268 } catch (final IOException e) {/* ignore close errors */ 269 } 270 super.epmd = null; 271 } 272 273 /** 274 * Accept an incoming connection from a remote node. A call to this method 275 * will block until an incoming connection is at least attempted. 276 * 277 * @return a connection to a remote node. 278 * 279 * @exception java.io.IOException 280 * if a remote node attempted to connect but no common 281 * protocol was found. 282 * 283 * @exception OtpAuthException 284 * if a remote node attempted to connect, but was not 285 * authorized to connect. 286 */ accept()287 public OtpConnection accept() throws IOException, OtpAuthException { 288 OtpTransport newsock = null; 289 290 while (true) { 291 try { 292 newsock = sock.accept(); 293 return new OtpConnection(this, newsock); 294 } catch (final IOException e) { 295 try { 296 if (newsock != null) { 297 newsock.close(); 298 } 299 } catch (final IOException f) {/* ignore close errors */ 300 } 301 throw e; 302 } 303 } 304 } 305 306 /** 307 * Open a connection to a remote node. 308 * 309 * @param other 310 * the remote node to which you wish to connect. 311 * 312 * @return a connection to the remote node. 313 * 314 * @exception java.net.UnknownHostException 315 * if the remote host could not be found. 316 * 317 * @exception java.io.IOException 318 * if it was not possible to connect to the remote node. 319 * 320 * @exception OtpAuthException 321 * if the connection was refused by the remote node. 322 */ connect(final OtpPeer other)323 public OtpConnection connect(final OtpPeer other) throws IOException, 324 UnknownHostException, OtpAuthException { 325 return new OtpConnection(this, other); 326 } 327 } 328