/** * Connects the Link to the remote Node. Exchanges the NodeIDs * * @return True if the Link successfully connected to the remote Link * @//throws JCSPNetworkException * Thrown if something goes wrong during the connection */ public override Boolean connect() //throws JCSPNetworkException { // First check if we are connected. if (this.connected) { return(true); } // Flag to determine if we are connected at the end of the process. Boolean toReturn = false; try { // Write the string representation of our NodeID to the remote Node this.txStream.Write(Node.getInstance().getNodeID().toString()); this.txStream.Flush(); // Read in the response from the opposite Node String response = this.rxStream.ReadString(); // Either the connection has been accepted (no connection to this Node exists on the opposite Node) or // it has not. The opposite Node sends OK in the first instance. if (response.Equals("OK", StringComparison.OrdinalIgnoreCase)) { // The connection is to be kept. Log, and set toReturn to true Node.log.log(this.GetType(), "Link to " + this.remoteAddress.toString() + " connected"); toReturn = true; } // Read in Remote NodeID as string NodeID otherID = NodeID.parse(this.rxStream.ReadString()); // First check we have a tcpip Node connection. This should always be the case if (otherID.getNodeAddress() is TCPIPNodeAddress) { // Set address and NodeID. If we are not connected then this NodeID can be used to // get the actual Link from the LinkManager this.remoteAddress = (TCPIPNodeAddress)otherID.getNodeAddress(); this.remoteID = otherID; // Set connected to toReturn this.connected = toReturn; return(toReturn); } // We do not have a tcpip? Should never really happen however. Log and throw Exception Node.err.log(this.GetType(), "Tried to connect a TCPIPLink to a non TCPIP connection"); throw new JCSPNetworkException("Tried to connect a TCPIPLink to a non TCPIP connection"); } catch (IOException ioe) { // Something went wrong during the connection process. Log and throw exception. Node.err.log(this.GetType(), "Failed to connect TCPIPLink to: " + this.remoteAddress.getAddress()); throw new JCSPNetworkException("Failed to connect TCPIPLink to: " + this.remoteAddress.getAddress()); } }
/** * Creates new TCPIPLink from a Socket. This is used internally by JCSP * * @param socket * The socket to create the TCPIPLink with * @param nodeID * The NodeID of the remote Node * @//throws JCSPNetworkException * Thrown if there is a problem during the connection */ internal TCPIPLink(Socket socket, NodeID nodeID) //throws JCSPNetworkException { try { // Set the socket property this.socket = socket; // Set TcpNoDelay //socket.setTcpNoDelay(!TCPIPLink.NAGLE); socket.NoDelay = !TCPIPLink.NAGLE; // Set the input and output streams for the Link //this.rxStream = new BinaryReader(new BufferedInputStream(socket.getInputStream(), TCPIPLink.BUFFER_SIZE)); //this.txStream = new BinaryWriter(new BufferedOutputStream(socket.getOutputStream(), TCPIPLink.BUFFER_SIZE)); //this.rxStream = new BinaryReader(new BufferedInputStream(this.socket.getInputStream(), TCPIPLink.BUFFER_SIZE)); this.rxStream = new BinaryReader(new NetworkStream(this.socket)); //this.txStream = new BinaryWriter(new BufferedOutputStream(this.socket.getOutputStream(), TCPIPLink.BUFFER_SIZE)); this.txStream = new BinaryWriter(new NetworkStream(this.socket)); // Set the NodeID this.remoteID = nodeID; // Set the remote address this.remoteAddress = (TCPIPNodeAddress)this.remoteID.getNodeAddress(); // Set connected to true this.connected = true; // Log Link creation and Link connection Node.log.log(this.GetType(), "Link created to " + nodeID.toString()); Node.log.log(this.GetType(), "Link to " + nodeID.toString() + " connected"); } catch (IOException ioe) { // Something went wrong during the creation. Log and throw exception Node.err.log(this.GetType(), "Failed to create Link to " + nodeID.toString()); throw new JCSPNetworkException("Failed to create TCPIPLink to: " + nodeID.getNodeAddress().getAddress()); } }
/** * The run method for the TCPIPLinkServer process */ public override void run() { // Log start of Link Server Node.log.log(this.GetType(), "TCPIP Link Server started on " + this.listeningAddress.getAddress()); try { // Now we loop until something goes wrong while (true) { // Receive incoming connection Socket incoming = this.serv.Accept(); //IPEndPoint remoteEndPoint = (IPEndPoint) incoming.RemoteEndPoint; //Debug.WriteLine("Accepted connection from {0}:{1}.", remoteEndPoint.Address, remoteEndPoint.Port); // Log Node.log.log(this.GetType(), "Received new incoming connection"); // Set TcpNoDelay incoming.NoDelay = true; // Now we want to receive the connecting Node's NodeID NetworkStream networkStream = new NetworkStream(incoming); // Receive remote NodeID and parse String otherID = new BinaryReader(networkStream).ReadString(); NodeID remoteID = NodeID.parse(otherID); // First check we have a tcpip Node connection if (remoteID.getNodeAddress() is TCPIPNodeAddress) { // Create an output stream from the Socket BinaryWriter outStream = new BinaryWriter(networkStream); // Now Log that we have received a connection Node.log.log(this.GetType(), "Received connection from: " + remoteID.toString()); // Check if already connected if (requestLink(remoteID) == null) { // No existing connection to incoming Node exists. Keep connection // Write OK to the connecting Node outStream.Write("OK"); outStream.Flush(); // Send out our NodeID outStream.Write(Node.getInstance().getNodeID().toString()); outStream.Flush(); // Create Link, register, and start. TCPIPLink link = new TCPIPLink(incoming, remoteID); registerLink(link); new ProcessManager(link).start(); } else { // We already have a connection to the incoming Node // Log failed connection Node.log.log(this.GetType(), "Connection to " + remoteID + " already exists. Informing remote Node."); // Write EXISTS to the remote Node outStream.Write("EXISTS"); outStream.Flush(); // Send out NodeID. We do this so the opposite Node can find its own connection outStream.Write(Node.getInstance().getNodeID().toString()); outStream.Flush(); // Close socket incoming.Close(); } } // Address is not a TCPIP address. Close socket. This will cause an exception on the opposite Node else { incoming.Close(); } } } catch (IOException ioe) { // We can't really recover from this. This may happen if the network connection was lost. // Log and fail Node.err.log(this.GetType(), "TCPIPLinkServer failed. " + ioe.Message); } }
/** * Creates a new Link or gets an existing one from the the given NodeID. * * @param nodeID * NodeID of the Node to connect to. * @return A Link connected to the remote Node of given NodeID * @//throws JCSPNetworkException * Thrown if there is a problem connecting to the Node * @//throws ArgumentException * Thrown if an attempt is made to connect to the local Node */ public static Link getLink(NodeID nodeID) ////throws JCSPNetworkException, ArgumentException { if (nodeID.equals(Node.getInstance().getNodeID())) { throw new ArgumentException("Attempted to connect to the local Node"); } // Log start of Link creation Node.log.log(typeof(LinkFactory), "Trying to get link to " + nodeID.toString()); // First check if Link to NodeID exists. Request the Link from the Link Manager Link toReturn = LinkManager.getInstance().requestLink(nodeID); if (toReturn != null) { // A Link already exists to given NodeID. Log and return existing Link Node.log.log(typeof(LinkFactory), "Link to " + nodeID.toString() + " already exists. Returning existing Link"); return(toReturn); } // An existing Link does not exist within the Link Manager. Log, and then create Link via the address Node.log.log(typeof(LinkFactory), "Link does not exist to " + nodeID.toString() + ". Creating new Link"); toReturn = nodeID.getNodeAddress().createLink(); // Now attempt to connect the Link. If connect fails, then the opposite node already has a connection to us. // This may occur during connection if the opposite end registered its Link prior to us doing so. In such // a circumstance, the Link should eventually appear in the LinkManager. if (!toReturn.connect()) { // Connect failed. Get NodeID of remote Node (this will have been set during the connect operation) NodeID remoteID = toReturn.getRemoteNodeID(); // Log failed connect Node.log.log(typeof(LinkFactory), "Failed to connect to " + remoteID.toString()); // Set the Link to return to null toReturn = null; // Loop until the Link is connected. This is a possible weakness. Although it is believed that the // opposite end will eventually connect, we may have a problem if this continually loops. For information, // log every attempt. while (toReturn == null) { try { // Go to sleep for a bit, and give the Link a chance to register Thread.Sleep(100); // Log start of attempt Node.log.log(typeof(LinkFactory), "Attempting to retrieve Link to " + remoteID.toString()); // Retrieve Link from LinkManager toReturn = LinkManager.getInstance().requestLink(remoteID); } catch (ThreadInterruptedException ie) { // Ignore. Should never really happen } } // Return the Link retrieved from the LinkManager return(toReturn); } // Connection succeeded. Register Link with the LinkManager toReturn.registerLink(); // Now start the Link ProcessManager proc = new ProcessManager(toReturn); proc.setPriority(toReturn.priority); proc.start(); // Return the Link return(toReturn); }