private void AsyncReceive(IAsyncResult ar) { bool readAsync = false; do { if (receiveState == INIT_RECEIVE) { buffer = new byte[48]; receivedLength = 0; receiveState = HEADER_RECEIVE; receivedMessage = new SpreadMessage(); } else { if (receivedLength != buffer.Length) { int size = stream.EndRead(ar); if (size == 0) throw new SpreadException("Connection closed while reading"); receivedLength += size; } if (receivedLength == buffer.Length) switch (receiveState) { case HEADER_RECEIVE: byte[] header = buffer; int headerIndex = 0; // Get service type. //////////////////// receivedMessage.ServiceType = toInt(header, headerIndex); headerIndex += 4; // Get the sender. ////////////////// /// receivedMessage.Sender = toGroup(header, headerIndex); headerIndex += MAX_GROUP_NAME; // Get the number of groups. //////////////////////////// numGroups = toInt(header, headerIndex); headerIndex += 4; // Get the hint/type. ///////////////////// int hint = toInt(header, headerIndex); headerIndex += 4; // Get the data length. /////////////////////// int dataLen = toInt(header, headerIndex); headerIndex += 4; // Does the header need to be flipped? // (Checking for a daemon server endian-mismatch) ///////////////////////////////////////////////// if(sameEndian(receivedMessage.ServiceType) == false) { // Flip them. ///////////// receivedMessage.ServiceType = flip(receivedMessage.ServiceType); numGroups = flip(numGroups); dataLen = flip(dataLen); // The daemon endian-mismatch. ////////////////////////////// daemonEndianMismatch = true; } else { // The daemon endian-mismatch. ////////////////////////////// daemonEndianMismatch = false; } receivedMessage.Data = new byte[dataLen]; // Is this a regular message? ///////////////////////////// if( receivedMessage.IsRegular || receivedMessage.IsReject ) { // Does the hint need to be flipped? // (Checking for a sender endian-mismatch) ////////////////////////////////////////// if(sameEndian(hint) == false) { hint = flip(hint); receivedMessage.EndianMismatch = true; } else { receivedMessage.EndianMismatch = false; } // Get the type from the hint. ////////////////////////////// hint = clearEndian(hint); hint >>= 8; hint &= 0x0000FFFF; receivedMessage.Type = (short)hint; } else { // This is not a regular message. ///////////////////////////////// receivedMessage.Type = -1; receivedMessage.EndianMismatch = false; } if( receivedMessage.IsReject ) { buffer = new byte[4]; receivedLength = 0; receiveState = OLD_TYPE_RECEIVE; } else { buffer = new byte[numGroups * MAX_GROUP_NAME]; receivedLength = 0; receiveState = GROUPS_RECEIVE; } break; case OLD_TYPE_RECEIVE: int oldType = toInt(buffer, 0); if ( sameEndian(receivedMessage.ServiceType) == false ) oldType = flip(oldType); receivedMessage.ServiceType = (SpreadMessage.REJECT_MESS | oldType); buffer = new byte[numGroups * MAX_GROUP_NAME]; receivedLength = 0; receiveState = GROUPS_RECEIVE; break; case GROUPS_RECEIVE: // Clear the endian type. ///////////////////////// receivedMessage.ServiceType = clearEndian(receivedMessage.ServiceType); // Get the groups from the buffer. ////////////////////////////////// for(int bufferIndex = 0 ; bufferIndex < buffer.Length ; bufferIndex += MAX_GROUP_NAME) { // Translate the name into a group and add it to the vector. //////////////////////////////////////////////////////////// receivedMessage.AddGroup(toGroup(buffer, bufferIndex)); } buffer = receivedMessage.Data; receivedLength = 0; receiveState = DATA_RECEIVE; break; case DATA_RECEIVE: // Is it a membership message? ////////////////////////////// if(receivedMessage.IsMembership) { // Create a membership info object. /////////////////////////////////// receivedMessage.membershipInfo = new MembershipInfo(this, receivedMessage, daemonEndianMismatch); // Is it a regular membership message? ////////////////////////////////////// if(receivedMessage.membershipInfo.IsRegularMembership) { // Find which of these groups is the local connection. ////////////////////////////////////////////////////// receivedMessage.Type = (short)receivedMessage.groups.IndexOf(PrivateGroup); } } else { // There's no membership info. ////////////////////////////// receivedMessage.membershipInfo = null; } if (OnRegularMessage !=null && receivedMessage.IsRegular) OnRegularMessage(receivedMessage); else if (OnMembershipMessage != null && receivedMessage.IsMembership) OnMembershipMessage(receivedMessage); else { lock (rsynchro) { messageWaiting = true; Monitor.Pulse(rsynchro); Monitor.Wait(rsynchro); } } buffer = new byte[48]; receivedLength = 0; receiveState = HEADER_RECEIVE; receivedMessage = new SpreadMessage(); break; } } try { // read sync if data available while(stream.DataAvailable && receivedLength < buffer.Length) { int size = stream.Read(buffer,receivedLength,buffer.Length-receivedLength); if (size == 0) throw new SpreadException("Connection closed while reading"); receivedLength += size; } if (receivedLength != buffer.Length) { // no more data - continue async read stream.BeginRead(buffer,receivedLength,buffer.Length-receivedLength,new AsyncCallback(AsyncReceive),null); readAsync = true; } } catch (Exception e) { throw new SpreadException("BeginRead(): " + e); } } while (!readAsync); }
// Sends the message. ///////////////////// /** * mcasts a message. The message will be sent to all the groups specified in * the message. * * @param message the message to mcast * @throws SpreadException if there is no connection or if there is any error sending the message */ public void Multicast(SpreadMessage message) { // Check if we're connected. //////////////////////////// if(connected == false) { throw new SpreadException("Not connected."); } // The groups this message is going to. /////////////////////////////////////// SpreadGroup[] groups = message.Groups; // The message data. //////////////////// byte[] data = message.Data; // Calculate the total number of bytes. /////////////////////////////////////// int numBytes = 16; // serviceType, numGroups, type/hint, dataLen numBytes += MAX_GROUP_NAME; // private group numBytes += (MAX_GROUP_NAME * groups.Length); // groups if (numBytes + data.Length > MAX_MESSAGE_LENGTH ) { throw new SpreadException("Message is too long for a Spread Message"); } // Allocate the send buffer. //////////////////////////// byte[] buffer = new byte[numBytes]; int bufferIndex = 0; // The service type. //////////////////// toBytes(message.ServiceType, buffer, bufferIndex); bufferIndex += 4; // The private group. ///////////////////// toBytes(group, buffer, bufferIndex); bufferIndex += MAX_GROUP_NAME; // The number of groups. //////////////////////// toBytes(groups.Length, buffer, bufferIndex); bufferIndex += 4; // The service type and hint. ///////////////////////////// toBytes(((int)message.Type << 8) & 0x00FFFF00, buffer, bufferIndex); bufferIndex += 4; // The data length. /////////////////// toBytes(data.Length, buffer, bufferIndex); bufferIndex += 4; // The group names. /////////////////// for(int i = 0 ; i < groups.Length ; i++) { toBytes(groups[i], buffer, bufferIndex); bufferIndex += MAX_GROUP_NAME; } try { stream.Write(buffer,0,buffer.Length); stream.Write(data,0,data.Length); } catch(Exception e) { throw new SpreadException("Write(): " + e.ToString()); } }
// Receives numMessages new messages. ///////////////////////////////////// /** * Receives <code>numMessages</code> messages on the connection and returns them in an array. * If there are not <code>numMessages</code> messages waiting, the call will block until there are * enough messages available. * * @param numMessages the number of messages to receive * @return an array of messages * @throws SpreadException if there is no connection or if there is any error reading the messages */ public SpreadMessage[] Receive(int numMessages) { // Allocate the messages array. /////////////////////////////// SpreadMessage[] messages = new SpreadMessage[numMessages]; for(int i = 0 ; i < numMessages ; i++) { messages[i] = Receive(); } // Return the array. //////////////////// return messages; }
// Disconnects from the spread daemon. ////////////////////////////////////// /** * Disconnects the connection to the daemon. Nothing else should be done with this connection * after disconnecting it. * * @throws SpreadException if there is no connection or there is an error disconnecting * @see SpreadConnection#connect(InetAddress, int, String, boolean, boolean) */ public void Disconnect() { // Check if we're connected. //////////////////////////// if(connected == false) { throw new SpreadException("Not connected."); } // Get a new message. ///////////////////// SpreadMessage killMessage = new SpreadMessage(); // Send it to our private group. //////////////////////////////// killMessage.AddGroup(group); // Set the service type. //////////////////////// killMessage.ServiceType = SpreadMessage.KILL_MESS; // Send the message. //////////////////// Multicast(killMessage); // Close the socket. //////////////////// try { socket.Close(); } catch(Exception e) { throw new SpreadException("close(): " + e); } }
// Sends the array of messages. /////////////////////////////// /** * mcasts an array of messages. Each message will be sent to all the groups specified in * the message. * * @param messages the messages to mcast * @throws SpreadException if there is no connection or if there is any error sending the messages */ public void Multicast(SpreadMessage[] messages) { // Go through the array. //////////////////////// for(int i = 0 ; i < messages.Length ; i++) { // Send this message. ///////////////////// Multicast(messages[i]); } }
public void Leave() { // Check if we can leave. ///////////////////////// if(connection == null) { throw new SpreadException("No group to leave."); } // Get a new message. ///////////////////// SpreadMessage leaveMessage = new SpreadMessage(); // Set the group we're sending to. ////////////////////////////////// leaveMessage.AddGroup(name); // Set the service type. //////////////////////// leaveMessage.ServiceType = SpreadMessage.LEAVE_MESS; // Send the message. //////////////////// connection.Multicast(leaveMessage); // No longer connected. /////////////////////// connection = null; }
// Constructor. /////////////// internal MembershipInfo(SpreadConnection connection,SpreadMessage message, bool daemonEndianMismatch) { // Set local variables. /////////////////////// this.serviceType = message.ServiceType; this.group = message.Sender; this.members = message.Groups; // Is this a regular membership message. //////////////////////////////////////// if(IsRegularMembership) { // Extract the groupID. /////////////////////// int dataIndex = 0; int[] id = new int[3]; id[0] = SpreadConnection.toInt(message.Data, dataIndex); dataIndex += 4; id[1] = SpreadConnection.toInt(message.Data, dataIndex); dataIndex += 4; id[2] = SpreadConnection.toInt(message.Data, dataIndex); dataIndex += 4; // Endian-flip? /////////////// if(daemonEndianMismatch) { id[0] = SpreadConnection.flip(id[0]); id[1] = SpreadConnection.flip(id[1]); id[2] = SpreadConnection.flip(id[2]); } // Create the group ID. /////////////////////// this.groupID = new GroupID(id[0], id[1], id[2]); // Get the number of groups. //////////////////////////// int numGroups = SpreadConnection.toInt(message.Data, dataIndex); if(daemonEndianMismatch) { numGroups = SpreadConnection.flip(numGroups); } dataIndex += 4; // Get the groups. ////////////////// this.groups = new SpreadGroup[numGroups]; for(int i = 0 ; i < numGroups ; i++) { this.groups[i] = connection.toGroup(message.Data, dataIndex); dataIndex += SpreadConnection.MAX_GROUP_NAME; } } }
public void Join(SpreadConnection c, string groupName) { // Check if this group has already been joined. /////////////////////////////////////////////// if(this.connection != null) { throw new SpreadException("Already joined."); } // Set member variables. //////////////////////// this.connection = c; this.name = groupName; // Error check the name. //////////////////////// byte[] bytes; try { bytes = System.Text.Encoding.ASCII.GetBytes(name); } catch(Exception e) { throw new SpreadException("Encoding not supported: "+e); } for(int i = 0 ; i < bytes.Length ; i++) { // Make sure the byte (character) is within the valid range. //////////////////////////////////////////////////////////// if((bytes[i] < 36) || (bytes[i] > 126)) { throw new SpreadException("Illegal character in group name."); } } // Get a new message. ///////////////////// SpreadMessage joinMessage = new SpreadMessage(); // Set the group we're sending to. ////////////////////////////////// joinMessage.AddGroup(name); // Set the service type. //////////////////////// joinMessage.ServiceType = SpreadMessage.JOIN_MESS; // Send the message. //////////////////// connection.Multicast(joinMessage); }
private void DisplayMessage(SpreadMessage msg) { try { Console.WriteLine("*****************RECTHREAD Received Message************"); if(msg.IsRegular) { Console.Write("Received a "); if(msg.IsUnreliable) Console.Write("UNRELIABLE"); else if(msg.IsReliable) Console.Write("RELIABLE"); else if(msg.IsFifo) Console.Write("FIFO"); else if(msg.IsCausal) Console.Write("CAUSAL"); else if(msg.IsAgreed) Console.Write("AGREED"); else if(msg.IsSafe) Console.Write("SAFE"); Console.WriteLine(" message."); Console.WriteLine("Sent by " + msg.Sender + "."); Console.WriteLine("Type is " + msg.Type + "."); if(msg.EndianMismatch == true) Console.WriteLine("There is an endian mismatch."); else Console.WriteLine("There is no endian mismatch."); SpreadGroup[] groups = msg.Groups; Console.WriteLine("To " + groups.Length + " groups."); byte[] data = msg.Data; Console.WriteLine("The data is " + data.Length + " bytes."); Console.WriteLine("The message is: " + System.Text.Encoding.ASCII.GetString(data)); } else if ( msg.IsMembership ) { MembershipInfo info = msg.MembershipInfo; if(info.IsRegularMembership) { //SpreadGroup[] groups = msg.Groups; SpreadGroup[] groups = info.Members; Console.WriteLine("Received a REGULAR membership."); Console.WriteLine("For group " + info.Group + "."); Console.WriteLine("With " + groups.Length + " members."); Console.WriteLine("Members: "); // + msg.Type + "."); for(int i = 0 ; i < groups.Length ; i++) Console.WriteLine(" " + groups[i]); Console.WriteLine("Group ID is " + info.GroupID); Console.Write("Due to "); if(info.IsCausedByJoin) { Console.WriteLine("the JOIN of " + info.Joined + "."); } else if(info.IsCausedByLeave) { Console.WriteLine("the LEAVE of " + info.Left + "."); } else if(info.IsCausedByDisconnect) { Console.WriteLine("the DISCONNECT of " + info.Disconnected + "."); } else if(info.IsCausedByNetwork) { SpreadGroup[] stayed = info.Stayed; Console.WriteLine("NETWORK change."); Console.WriteLine("VS set has " + stayed.Length + " members:"); for(int i = 0 ; i < stayed.Length ; i++) Console.WriteLine(" " + stayed[i]); } } else if(info.IsTransition) { Console.WriteLine("Received a TRANSITIONAL membership for group " + info.Group); } else if(info.IsSelfLeave) { Console.WriteLine("Received a SELF-LEAVE message for group " + info.Group); } } else if ( msg.IsReject ) { // Received a Reject message Console.Write("Received a "); if(msg.IsUnreliable) Console.Write("UNRELIABLE"); else if(msg.IsReliable) Console.Write("RELIABLE"); else if(msg.IsFifo) Console.Write("FIFO"); else if(msg.IsCausal) Console.Write("CAUSAL"); else if(msg.IsAgreed) Console.Write("AGREED"); else if(msg.IsSafe) Console.Write("SAFE"); Console.WriteLine(" REJECTED message."); Console.WriteLine("Sent by " + msg.Sender + "."); Console.WriteLine("Type is " + msg.Type + "."); if(msg.EndianMismatch == true) Console.WriteLine("There is an endian mismatch."); else Console.WriteLine("There is no endian mismatch."); SpreadGroup[] groups = msg.Groups; Console.WriteLine("To " + groups.Length + " groups."); byte[] data = msg.Data; Console.WriteLine("The data is " + data.Length + " bytes."); Console.WriteLine("The message is: " + System.Text.Encoding.ASCII.GetString(data)); } else { Console.WriteLine("Message is of unknown type: " + msg.ServiceType ); } } catch(Exception e) { Console.WriteLine(e); Environment.Exit(1); } }
public void messageReceived(SpreadMessage message) { DisplayMessage(message); }
private void UserCommand() { // Show the prompt. /////////////////// Console.Write("\n" + "User> "); // Get the input. ///////////////// string[] tokens = Console.ReadLine().Split(new Char[] {' '}); // Check what it is. //////////////////// SpreadMessage msg; char command = tokens[0].Length>0?tokens[0][0]:'\n'; try { switch(command) { //JOIN case 'j': // Join the group. ////////////////// if(tokens.Length > 1) { group = new SpreadGroup(); group.Join(connection, tokens[1]); Console.WriteLine("Joined " + group + "."); } else { System.Console.Error.WriteLine("No group name."); } break; //LEAVE case 'l': // Leave the group. /////////////////// if(group != null) { group.Leave(); Console.WriteLine("Left " + group + "."); } else { Console.WriteLine("No group to leave."); } break; //SEND case 's': // Get a new outgoing message. ////////////////////////////// msg = new SpreadMessage(); msg.IsSafe = true; // Add the groups. ////////////////// for(int i=1;i < tokens.Length;i++) msg.AddGroup(tokens[i]); // Get the message. /////////////////// Console.Write("Enter message: "); msg.Data = System.Text.Encoding.ASCII.GetBytes(Console.ReadLine()); // Send it. /////////// connection.Multicast(msg); // Increment the sent message count. //////////////////////////////////// numSent++; // Show how many were sent. /////////////////////////// Console.WriteLine("Sent message " + numSent + "."); break; //BURST case 'b': // Get a new outgoing message. ////////////////////////////// msg = new SpreadMessage(); msg.IsSafe = true;; // Get the group. ///////////////// if(tokens.Length > 1) { msg.AddGroup(tokens[1]); } else { Console.Error.WriteLine("No group name."); break; } // Get the message size. //////////////////////// Console.Write("Enter the size of each message: "); int size = int.Parse(Console.ReadLine()); if(size < 0) size = 20; // Send the messages. ///////////////////// Console.WriteLine("Sending 10 messages of " + size + " bytes."); byte[] data = new byte[size]; for(int i = 0 ; i < size ; i++) { data[i] = 0; } for(int i = 0 ; i < 10 ; i++) { // Increment the sent message count. //////////////////////////////////// numSent++; // Set the message data. //////////////////////// byte[] mess = System.Text.Encoding.ASCII.GetBytes("mess num " + i); Array.Copy(mess, 0, data, 0, mess.Length); msg.Data = data; // Send the message. //////////////////// connection.Multicast(msg); Console.WriteLine("Sent message " + (i + 1) + " (total " + numSent + ")."); } break; //RECEIVE case 'r': if(listening == false) { // Receive a message. ///////////////////// DisplayMessage(connection.Receive()); } break; //POLL case 'p': if(listening == false) { // Poll. //////// if(connection.Poll() == true) { Console.WriteLine("There is a message waiting."); } else { Console.WriteLine("There is no message waiting."); } } break; //THREAD case 't': if(listening) { connection.OnRegularMessage -= handler; connection.OnMembershipMessage -= handler; if (rt.threadSuspended) lock(rt) { Monitor.Pulse(rt); rt.threadSuspended = false; } } else { connection.OnRegularMessage += handler; connection.OnMembershipMessage += handler; lock(rt) { rt.threadSuspended = true; } } listening = !listening; break; //QUIT case 'q': // Disconnect. ////////////// connection.Disconnect(); // Quit. //////// Environment.Exit(0); break; default: // Unknown command. /////////////////// Console.WriteLine("Unknown command"); // Show the menu again. /////////////////////// PrintMenu(); break; } } catch(Exception e) { Console.WriteLine(e); Environment.Exit(1); } }
public Flooder(String user, int numMessages, int numBytes, String address, int port, bool readOnly, bool writeOnly) { try { // Start timer. /////////////// DateTime startTime = DateTime.Now; // Connect. /////////// SpreadConnection connection = new SpreadConnection(); connection.Connect(address, port, user, false, false); string privateName = connection.PrivateGroup.ToString(); // Join. //////// SpreadGroup group = new SpreadGroup(); if(readOnly) { Console.WriteLine("Only receiving messages"); group.Join(connection, "flooder"); } else if(writeOnly) { Console.WriteLine("Starting multicast of " + numMessages + " messages, " + numBytes + " bytes each (self discarding)."); } else { group.Join(connection, "flooder"); Console.WriteLine("Starting multicast of " + numMessages + " messages, " + numBytes + " bytes each."); } // The outgoing message. //////////////////////// SpreadMessage mout = null; if(readOnly == false) { mout = new SpreadMessage(); mout.IsSafe = true; mout.Data = new byte[numBytes]; mout.AddGroup("flooder"); } // Send/Receive. //////////////// for(int i = 1 ; i <= numMessages ; i++) { // Send. //////// if(readOnly == false) { connection.Multicast(mout); } // Receive. /////////// if((readOnly) || ((i > 50) && (writeOnly == false))) { SpreadMessage min; do { min = connection.Receive(); } while((readOnly == false) && (privateName.Equals(min.Sender.ToString()) == false)); } // Report. ////////// if((i % 1000) == 0) { Console.WriteLine("Completed " + i + " messages"); } } // Stop timer. ////////////// DateTime stopTime = DateTime.Now; TimeSpan time = stopTime.Subtract(startTime); double Mbps = numBytes; Mbps *= numMessages; Mbps *= 8; if((readOnly == false) && (writeOnly == false)) Mbps *= 2; Mbps *= 1000; Mbps /= time.TotalMilliseconds; Mbps /= (1024 * 1024); Console.WriteLine("Time: " + time + "ms (" + (int)Mbps + "." + (((int)(Mbps * 100)) % 100) + " Mbps)"); } catch(Exception e) { Console.WriteLine(e); } }