/** * Creates a new Link, or retrieves an existing one, from a NodeAddress * * @param addr * The NodeAddress of the Node to connect to * @return A new Link connected to the node at the given NodeAddress * @//throws JCSPNetworkException * Thrown if anything goes wrong during the connection */ public static Link getLink(NodeAddress addr) ////throws JCSPNetworkException { // Log start of creation Node.log.log(typeof(LinkFactory), "Trying to get link to " + addr.toString()); // Create Link from address Link toReturn = addr.createLink(); Console.WriteLine("Finished creating link NodeID " + toReturn.remoteID); // 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()); Console.WriteLine("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 new ProcessManager(toReturn).start(); // Return the Link return(toReturn); }
/** * 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); }
/** * The run method for the BNS process */ public void run() { // Create the channel to receive incoming messages on. The index is 2. NetAltingChannelInput In = NetChannel.numberedNet2One(2, new BNSNetworkMessageFilter.FilterRX()); // We now wish to alternate upon this channel and the link lost channel Alternative alt = new Alternative(new Guard[] { this.lostLink, In }); // Loop forever while (true) { // Select next available Guard. Give priority to link failure switch (alt.priSelect()) { // We have lost the connection to a Node case 0: // Read in the NodeID of the lost Node NodeID lostNode = (NodeID)this.lostLink.read(); // Log loss of connection Node.log.log(this.GetType(), "Lost Link to: " + lostNode.toString()); // Remove the logged client this.loggedClients.Remove(lostNode); // Next get the ArrayList of any barriers registered by that Node ArrayList registeredBars = (ArrayList)this.barrierRegister[lostNode]; // If this ArrayList is null, we have no registrations if (registeredBars != null) { // There are registered barriers // Remove the list from the Hashmap this.barrierRegister.Remove(lostNode); // Now remove all the barriers registered by the Node for (IEnumerator enumerator = registeredBars.GetEnumerator(); enumerator.MoveNext();) { String toRemove = (String)enumerator.Current; this.registeredBarriers.Remove(toRemove); Node.log.log(this.GetType(), toRemove + " deregistered"); } } break; // We have received a new incoming message case 1: { // Read in the message BNSMessage message = (BNSMessage)In.read(); // Now behave based on the type of the message switch (message.type) { // We have received a logon message case BNSMessageProtocol.LOGON_MESSAGE: { // Log the logon attempt Node.log.log(this.GetType(), "Logon received from: " + message.serviceLocation.getNodeID().toString()); // try-catch loop. We don't want the BNS to fail try { // Check if the node is already logged on NetChannelOutput Out = (NetChannelOutput)this.loggedClients[message.serviceLocation.getNodeID()]; // If out is null, no previous logon received if (Out != null) { // This Node is already logged on. Send fail message // Log failed attempt Node.err.log(this.GetType(), message.serviceLocation.getNodeID().toString() + " already logged on. Rejecting"); // Create reply channel to the Node NetChannelOutput toNewRegister = NetChannel.one2net(message.serviceLocation, new BNSNetworkMessageFilter.FilterTX()); // Create the reply message BNSMessage reply = new BNSMessage(); reply.type = BNSMessageProtocol.LOGON_REPLY_MESSAGE; reply.success = false; // Asynchronously write to Node. We don't want the BNS to block toNewRegister.asyncWrite(reply); // Destroy the temporary channel toNewRegister.destroy(); } else { // Node hasn't previously registered // Log registration Node.log.log(this.GetType(), message.serviceLocation.getNodeID().toString() + " successfully logged on"); // Create the reply channel NetChannelOutput toNewRegister = NetChannel.one2net(message.serviceLocation, new BNSNetworkMessageFilter.FilterTX()); // Add the Node and reply channel to the logged clients map this.loggedClients.Add(message.serviceLocation.getNodeID(), toNewRegister); // Create a reply message BNSMessage reply = new BNSMessage(); reply.type = BNSMessageProtocol.LOGON_REPLY_MESSAGE; reply.success = true; // Write reply asynchronously to the logging on Node toNewRegister.asyncWrite(reply); } } catch (JCSPNetworkException jne) { // Catch any JCSPNetworkException. We don't let the BNS go down } break; } // A Node is attempting to register a Barrier case BNSMessageProtocol.REGISTER_REQUEST: { // Log registration attempt Node.log.log(this.GetType(), "Registeration for " + message.name + " received"); // Catch any JCSPNetworkException try { // Get the reply channel from our logged clients map NetChannelOutput Out = (NetChannelOutput)this.loggedClients[message.serviceLocation.getNodeID()]; // Check if the Node has logged on with us if (Out == null) { // The Node is not logged on. Send failure message Node.err.log(this.GetType(), "Registration failed. " + message.serviceLocation.getNodeID() + " not logged on"); // Create the channel to reply to Out = NetChannel.one2net(message.serviceLocation, new BNSNetworkMessageFilter.FilterTX()); // Create the reply message BNSMessage reply = new BNSMessage(); reply.type = BNSMessageProtocol.REGISTER_REPLY; reply.success = false; // Write message asynchronously to the Node Out.asyncWrite(reply); // Destroy the temporary channel Out.destroy(); } // The Node is registered. Now check if the name is else if (this.registeredBarriers.ContainsKey(message.name)) { // The name is already registered. Inform the register // Log the failed registration Node.err.log(this.GetType(), "Registration failed. " + message.name + " already registered"); // Create reply message BNSMessage reply = new BNSMessage(); reply.type = BNSMessageProtocol.RESOLVE_REPLY; reply.success = false; // Write the reply asynchronously. Do not block the BNS Out.asyncWrite(reply); } else { BNSMessage reply; // The name is not registered // Log successful registration Node.log.log(this.GetType(), "Registration of " + message.name + " succeeded."); // First check if any client end is waiting for this name ArrayList pending = (ArrayList)this.waitingResolves[message.name]; if (pending != null) { // We have waiting resolves. Complete for (IEnumerator enumerator = pending.GetEnumerator(); enumerator.MoveNext();) { NetChannelOutput toPending = null; // We now catch internally any JCSPNetworkException try { // Get the next waiting message BNSMessage msg = (BNSMessage)enumerator.Current; // Log resolve completion Node.log.log(this.GetType(), "Queued resolve of " + message.name + " by " + msg.serviceLocation.getNodeID() + " completed"); // Create channel to the resolver toPending = NetChannel.one2net(msg.serviceLocation, new BNSNetworkMessageFilter.FilterTX()); // Create the reply message reply = new BNSMessage(); reply.type = BNSMessageProtocol.RESOLVE_REPLY; reply.location = message.location; reply.success = true; // Write the reply asynchronously to the waiting resolver toPending.asyncWrite(reply); } catch (JCSPNetworkException jne) { // Something went wrong as we tried to send the resolution complete // message // Do nothing } finally { // Check if we need to destroy the temporary channel if (toPending != null) { toPending.destroy(); } } } // Remove the name from the pending resolves this.waitingResolves.Remove(message.name); } // We have completed any pending resolves. Now register the barrier this.registeredBarriers.Add(message.name, message.location); // Now add the registered barrier to the barriers registered by this Node ArrayList registered = (ArrayList)this.barrierRegister[message.serviceLocation.getNodeID()]; // If the ArrayList is null, we have no previous registrations if (registered == null) { // Create a new ArrayList to store the registered names registered = new ArrayList(); // Add it to the barrier register this.barrierRegister.Add(message.location.getNodeID(), registered); } // Add the name to the ArrayList registered.Add(message.name); // Log the successful registration Node.log.log(this.GetType(), message.name + " registered to " + message.location); // Create the reply message reply = new BNSMessage(); reply.type = BNSMessageProtocol.REGISTER_REPLY; reply.success = true; // Write the reply asynchronously to the Node Out.asyncWrite(reply); } } catch (JCSPNetworkException jne) { // Do nothing. Do not let the BNS break } break; } // We have received a resolve request case BNSMessageProtocol.RESOLVE_REQUEST: { // Log resolve request Node.log.log(this.GetType(), "Resolve request for " + message.name + " received"); // Catch any JCSPNetworkException try { // Check if the resolving Node is logged on NetChannelOutput Out = (NetChannelOutput)this.loggedClients[message.serviceLocation.getNodeID()]; // If the channel is null, then the Node has yet to log on with us if (Out == null) { // Node is not logged on // Log failed resolution Node.err.log(this.GetType(), "Resolve failed. " + message.serviceLocation.getNodeID() + " not logged on"); // Create connection to the receiver Out = NetChannel.one2net(message.serviceLocation, new BNSNetworkMessageFilter.FilterTX()); // Create the reply message BNSMessage reply = new BNSMessage(); reply.type = BNSMessageProtocol.RESOLVE_REPLY; reply.success = false; // Write message asynchronously to the Node Out.asyncWrite(reply); // Destroy the temporary channel Out.destroy(); } else { // Node is logged on. Now check if the name is already registered NetBarrierLocation loc = (NetBarrierLocation)this.registeredBarriers[message.name]; // If the location is null, then the name has not yet been registered if (loc == null) { // The name is not registered. We need to queue the resolve until it is // Log the queueing of the resolve Node.log.log(this.GetType(), message.name + " not registered. Queueing resolve by " + message.serviceLocation.getNodeID().toString()); // Check if any other resolvers are waiting for the channel ArrayList pending = (ArrayList)this.waitingResolves[message.name]; // If the ArrayList is null, no one else is waiting if (pending == null) { // No one else is waiting. Create a new list and add it to the waiting // resolves pending = new ArrayList(); this.waitingResolves.Add(message.name, pending); } // Add this resolve message to the list of waiting resolvers pending.Add(message); } else { // The location is not null. Send it to the resolver Node.log.log(this.GetType(), "Resolve request completed. " + message.name + " location being sent to " + message.serviceLocation.getNodeID()); // Create channel to the resolver NetChannelOutput toPending = NetChannel.one2net(message.serviceLocation, new BNSNetworkMessageFilter.FilterTX()); // Create the reply message BNSMessage reply = new BNSMessage(); reply.type = BNSMessageProtocol.RESOLVE_REPLY; reply.location = loc; reply.success = true; // Write the reply to the resolver asynchronously toPending.asyncWrite(reply); // Destroy the temporary channel toPending.destroy(); } } } catch (JCSPNetworkException jne) { // Something went wrong during the resolution. Ignore } break; } } break; } } } }