예제 #1
0
        public void Receive(ReceiveMessageEventArgs eventargs)
        {
            Message message = eventargs.m_message;

            if (!m_server.m_replicationService.IsMaster)
            {
                // TODO: reply, in future: redirect question?
                DebugInfo ("Got request intended for master.");
                m_server.m_replicationService.SendImNotMasterMessage (message);
                return;
            }

            // All we need from the request is the source
            // uri.
            DebugInfo ("Server {0} got request for sequence number from {1}", m_server.UserName, message.GetSourceUserName ());

            // Create response to the requester
            Message response = new Message ();
            response.SetSourceUri (m_server.UserName);
            response.SetDestinationUsers (message.GetSourceUserName ());
            response.SetMessageType ("sequencenumber");

            long nextSequenceNumber = GetSequenceNumber ();
            response.PushString (nextSequenceNumber.ToString ());

            // this is implictly a blocking call
            m_server.m_replicationService.ReplicateSequenceNumber (nextSequenceNumber);

            m_server.m_sendReceiveMiddleLayer.Send (response);
        }
예제 #2
0
 public void SendInfoMsgToPuppetMaster(string message, params object[] args)
 {
     Message m = new Message ();
     m.SetMessageType ("puppet_info");
     m.SetSourceUserName (m_server.UserName);
     m.SetDestinationUsers (PUPPET_MASTER);
     m.PushString (String.Format (message, args));
     m_server.m_puppetSendReceiveMiddleLayer.Send (m);
 }
예제 #3
0
        public string Lookup(string user)
        {
            lock (this){
                // TODO: This should later move into a lookup for
                // a list of users.
                // TODO: It should also implement a cache
                // to avoid remote invocations all the time.
                // TODO: Avoid restricted "SERVER" username
                // registrations at server end.

                // Lookup service knows the servers.
                // It will also check the cache at a later stage of
                // development.
                if (user.Equals ("SERVER"))
                {
                    // Return server 1. Will be changed later.
                    return m_client.CurrentMasterServer;
                }
                else if (user.Equals ("PUPPETMASTER"))
                {
                    DebugUncond ("Returning address for puppet master {0}", m_client.PuppetMasterAddress);
                    return m_client.PuppetMasterAddress;
                }

                // If not SERVER or in cache, create a new
                // lookup message destined to SERVER. Eventually,
                // lower layer will query for SERVER, and this
                // method will answer it.
                Message m = new Message ();
                m.SetSourceUserName (m_client.UserName);
                m.SetDestinationUsers ("SERVER");
                m.SetMessageType ("lookup");
                m.PushString (user); // This should change to a list later

                m_client.m_sendReceiveMiddleLayer.Send (m);
                // This thread will block here until the reset event is sent.
                // In this case, it happens when the Receive() method is invocated
                // upon getting a response.
                DebugInfo ("Sent Lookup request");
                m_oSignalEvent.WaitOne();
                DebugInfo ("Releasing block");
                m_oSignalEvent.Reset ();

                return m_lookupResponse;
            }
        }
예제 #4
0
 private Message PackUserTable()
 {
     Message m = new Message ();
     foreach (string user in m_server.m_userTableService.UserTable.Keys)
     {
         m.PushString (String.Format ("{0},{1}", user,
                                      m_server.m_userTableService.UserTable[user]));
     }
     m.PushString (m_server.m_userTableService.UserTable.Count.ToString ());
     return m;
 }
예제 #5
0
 private void HandleUserDisconnectReplication(string username, string replyTo)
 {
     m_server.m_userTableService.UserDisconnect (username);
     Message ack = new Message ();
     ack.SetMessageType ("replicate");
     ack.SetDestinationUsers (replyTo);
     ack.SetSourceUserName (m_server.UserName);
     ack.PushString (username);
     ack.PushString ("user_disconnect_ack");
     m_server.m_sendReceiveMiddleLayer.Send (ack);
 }
예제 #6
0
 private void HandleSequenceNumberReplication(string number, string replyTo)
 {
     m_server.m_sequenceNumberService.SetSequenceNumber (Int32.Parse (number));
     Message ack = new Message ();
     ack.SetMessageType ("replicate");
     ack.SetDestinationUsers (replyTo);
     ack.SetSourceUserName (m_server.UserName);
     ack.PushString (number);
     ack.PushString ("sequencenumber_ack");
     m_server.m_sendReceiveMiddleLayer.Send (ack);
 }
예제 #7
0
 public void SendImNotMasterMessage(Message msg)
 {
     DebugInfo ("Asking {0} to resend to {1}", msg.GetSourceUserName (), CurrentMaster);
     Message m = new Message ();
     m.SetMessageType ("resend");
     m.SetDestinationUsers (msg.GetSourceUserName ());
     m.MessageForResending = msg;
     m.SetSourceUserName (m_server.UserName);
     m.PushString (m_server.m_userTableService.Lookup (CurrentMaster));
     m_server.m_sendReceiveMiddleLayer.Send (m,msg.GetSourceUri (), msg.GetSourceUserName ());
 }
예제 #8
0
 public void ReplicateUserDisconnect(string username)
 {
     if (IsMaster)
     {
         DebugInfo ("Sending UserDisconnect replication request");
         Message m = new Message ();
         m.PushString (username);
         m.PushString ("user_disconnect");
         DistributeReplicationMessage (m);
     }
 }
예제 #9
0
 public void ReplicateSequenceNumber(long number)
 {
     if (IsMaster)
     {
         DebugInfo ("Sending sequence number ({0}) replication request", number);
         Message m = new Message ();
         m.PushString (number.ToString ());
         m.PushString ("sequencenumber"); // subtyped message
         DistributeReplicationMessage (m);
     }
 }
예제 #10
0
        public void Reserve(string description, List<string> userlist, List<int> slotlist)
        {
            // 1) Create reservation object
            // TODO: Make sure m_client VALIDATES the inputs?
            // TODO: At this point, we assume all requested slots are free.
            Reservation reservation = new Reservation ();
            reservation.m_description = description;
            reservation.m_slotNumberList = slotlist;
            reservation.m_userList = userlist;
            reservation.m_reservationState = CalendarServiceClient.ReservationState.INITIATED;
            reservation.m_acksForSlot = new Dictionary<int, int> ();
            reservation.m_initiator = m_client.UserName;

            // Update slot objects
            foreach (int i in slotlist)
            {
                // If slot is being encountered for the
                // first time...
                if (!m_numberToSlotMap.ContainsKey (i))
                {
                    DebugLogic ("Creating new slot instance for slot-number: {0}", i);

                    // Then create new slot.
                    // TODO: Probably need internal methods for this
                    Slot slot = new Slot ();
                    slot.m_calendarState = CalendarState.FREE;
                    slot.m_slotNumber = i;
                    slot.m_reservationsForThisSlot = new List<Reservation> ();
                    slot.m_preCommitList = new SortedList<int, Reservation> ();
                    slot.m_lockedReservation = -1;

                    // Add to int-to-slot-object map
                    m_numberToSlotMap.Add (i, slot);
                }

                // Update the slot's reservation list
                m_numberToSlotMap[i].m_reservationsForThisSlot.Add (reservation);
            }

            //DebugUncond ("----->>>> {0} {1} <<---", userlist.Count, userlist[0]);

            // Special case, book with yourself
            if (userlist.Count == 1 && userlist[0] == m_client.UserName)
            {
                // TODO: Check if slot is in action perhaps.
                foreach (int i in slotlist)
                {
                    Slot s = m_numberToSlotMap[i];
                    if (s.m_calendarState != CalendarServiceClient.CalendarState.ASSIGNED
                        && s.m_calendarState != CalendarServiceClient.CalendarState.BOOKED)
                    {
                        s.m_calendarState = CalendarServiceClient.CalendarState.ASSIGNED;
                        reservation.m_reservationState = CalendarServiceClient.ReservationState.COMMITTED;
                        s.m_lockedReservation = i;
                        return;
                    }
                }
            }

            // 2) Obtain sequence number
            reservation.m_sequenceNumber = m_client.GetSequenceNumber ();

            // 2) Maintain reservation session as per sequence number
            // Add reservation object to int-to-reservation-object map.
            m_activeReservationSessions.Add (reservation.m_sequenceNumber, reservation);

            DebugLogic ("Created reservation object for" +
                "[Desc: {0}, Users: {1}, Slots: {2} Seq: {3}]",description, userlist, slotlist, reservation.m_sequenceNumber);

            // Else, trim yourself out of the list (position 0).
            // Surely it is yourself, but sanity checks are good.
            if (m_client.UserName.Equals (userlist[0]))
            {
                userlist.RemoveAt(0);
            }

            // 3) Disseminate reservation request
            DebugLogic ("Dissemination reservation request " +
                "[Desc: {0}, Users: {1}, Slots: {2}]",description, userlist, slotlist);

            Message reservationRequest = new Message ();

            /* Message format for reservations (stack part) is as follows:
             *
             * - SubType TODO: Later register more types up there.
             * - ReservationSequenceNumber
             * - User NumberOfSlots
             * - NumberOfSlots
             * - Slot 1
             * - Slot 2
             * ...
             * - Slot NumberOfUsers
             * - Description
             */
            reservationRequest.SetDestinationUsers (userlist);
            reservationRequest.SetMessageType ("calendar");
            reservationRequest.SetSourceUserName (m_client.UserName);

            // Data part. Things will be pushed in the reverse order
            // of the format
            reservationRequest.PushString (description);

            // Since we're pushing on to a stack and would like
            // to retreive it in the same order at the other end.
            slotlist.Reverse ();
            foreach (int i in slotlist)
            {
                reservationRequest.PushString (i.ToString ());
            }

            reservationRequest.PushString (reservation.m_slotNumberList.Count.ToString ());
            reservationRequest.PushString (reservation.m_sequenceNumber.ToString ());
            reservationRequest.PushString ("reservationrequest");

            SendMessage (reservationRequest);
        }
예제 #11
0
        private void SendPreCommitMessage(Reservation res, int s)
        {
            // Now send a precommit message to everyone involved.
            // Party time!

            Message precommitMsg = new Message ();

            precommitMsg.SetSourceUserName (m_client.UserName);
            precommitMsg.SetDestinationUsers (res.m_userList);
            DebugLogic ("SENDING PRECOMMIT TO {0} many ppl for slot {1}", res.m_userList.Count, s);
            precommitMsg.SetMessageType ("calendar");
            precommitMsg.PushString (s.ToString ());
            precommitMsg.PushString (res.m_sequenceNumber.ToString ());
            precommitMsg.PushString ("precommit");
            SendMessage (precommitMsg);

            res.m_acksForSlot.Clear ();
        }
예제 #12
0
        private void ReservationAbortCohort(int reservationSequenceNumber, int s)
        {
            Slot slot = m_numberToSlotMap[s];

            Reservation oldReservation = m_activeReservationSessions[reservationSequenceNumber];
            oldReservation.m_slotNumberList.Remove (s);

            // The earlier reservation is now removed from this slot
            slot.m_reservationsForThisSlot.Remove (oldReservation);

            // If this was the last slot in contention for
            // the reservation...
            if (oldReservation.m_slotNumberList.Count == 0)
            {
                // ... then the reservation should be in ABORTED state. Sigh.
                oldReservation.m_reservationState = CalendarServiceClient.ReservationState.ABORTED;
            }

            // This slot is currently locked, only an abort can kill it.
            if (slot.m_lockedReservation == reservationSequenceNumber)
            {
                // Promote next reservation in precommit queue
                if (slot.m_preCommitList.Count > 0)
                {
                    slot.m_lockedReservation = slot.m_preCommitList.Keys[0]; // Lock top queue elements
                    slot.m_preCommitList.RemoveAt (0); // remove top element from queue.

                    Reservation newres = m_activeReservationSessions[slot.m_lockedReservation];

                    // Send a yes message for the succeeding reservation
                    Message yes = new Message ();
                    yes.SetDestinationUsers (m_activeReservationSessions[slot.m_lockedReservation].m_initiator);
                    yes.SetMessageType ("calendar");
                    yes.SetSourceUserName (m_client.UserName);
                    yes.PushString (slot.m_slotNumber.ToString ());
                    yes.PushString (newres.m_sequenceNumber.ToString ());
                    yes.PushString ("yes");

                    SendMessage (yes);
                }
                else
                {
                    // We don't have any more reservations for this slot, so
                    // let's keep it in the ACKNOWLEDGED state.
                    slot.m_calendarState = CalendarServiceClient.CalendarState.ACKNOWLEDGED;

                    // Release locks
                    slot.m_lockedReservation = -1;
                }
            }
            else
            {
                // This slot is in the precommit list
                slot.m_preCommitList.Remove (s);
            }
        }
예제 #13
0
        private void ReceiveReservationYes(Message m,
		                                      string src,
		                                      List<string> userlist,
		                                      int reservationSequenceNumber,
		                                      string messageSubType)
        {
            int s = Int32.Parse (m.PopString ());
            DebugLogic ("Received YES for slot {0}, reservation number {1}",s,reservationSequenceNumber);

            Slot slot = m_numberToSlotMap[s];
            Reservation res = m_activeReservationSessions[reservationSequenceNumber];

            int ackcount;
            if (res.m_acksForSlot.ContainsKey (s))
            {
                res.m_acksForSlot[s]++;
                ackcount = res.m_acksForSlot[s];
            }
            else
            {
                ackcount = 1;
                res.m_acksForSlot[s] = ackcount;
            }

            if (ackcount == res.m_userList.Count
                // the below two conditions are sanity checks.
                && res.m_reservationState != CalendarServiceClient.ReservationState.COMMITTED
                && m_numberToSlotMap[s].m_calendarState != CalendarServiceClient.CalendarState.ASSIGNED)
            {
                DebugLogic ("Woopee! I can haz slot! {0}", s);

                //send DoCommit
                Message docommitMsg = new Message ();
                docommitMsg.SetSourceUserName (m_client.UserName);
                docommitMsg.SetDestinationUsers (res.m_userList);
                docommitMsg.SetMessageType ("calendar");
                docommitMsg.PushString (s.ToString ());
                docommitMsg.PushString (reservationSequenceNumber.ToString ());
                docommitMsg.PushString ("docommit");
                SendMessage (docommitMsg);

                // If you have to send this, then you can commit.
                // TODO: Handle 2/1, 1/2 deadlock.
                slot.m_calendarState = CalendarServiceClient.CalendarState.ASSIGNED;
                res.m_reservationState = CalendarServiceClient.ReservationState.COMMITTED;
            }
        }
예제 #14
0
        private void ReceiveReservationRequest(Message m,
		                                        string src,
		                                        List<string> userlist,
		                                        int reservationSequenceNumber,
		                                        string messageSubType)
        {
            /* If I get a reservation request for a slot
             * that is either FREE or ACKNOWLEDGED, then
             * respond with an ACK, else if it is either
             * BOOKED, or ASSIGNED, then respond with a NACK
             */
            int numSlots = Int32.Parse (m.PopString ()); // number of slots
            List<int> slotlist = new List<int> (); // unpack all the slots
            for (int i = 0; i < numSlots; i++)
            {
                slotlist.Add (Int32.Parse (m.PopString ()));
            }

            string description = m.PopString (); // description
            DebugLogic ("Received Message:" +
                               "[{0}, {1}, {2}, {3}, {4}, {5}, {6}]",
                               src, userlist.ToString (), messageSubType, reservationSequenceNumber, numSlots, slotlist.ToString (), description);

            /* Message unpacked, now create a reservation object
             */

            if (m_activeReservationSessions.ContainsKey (reservationSequenceNumber))
            {
                DebugFatal ("Duplicate reservation request received {0}", reservationSequenceNumber);
            }

            /* Create reservation object
             */
            Reservation reservation = new Reservation ();
            reservation.m_description = description;
            reservation.m_sequenceNumber = reservationSequenceNumber;
            reservation.m_userList = userlist;
            reservation.m_slotNumberList = slotlist;
            reservation.m_initiator = src;

            /*
             * check if slots are free
             * and proceed to respond with an ACK or NACK.
             */
            List<int> availableslots = new List<int> ();
            foreach (int i in slotlist)
            {
                // If slot is being encountered for the
                // first time...
                if (!m_numberToSlotMap.ContainsKey (i))
                {
                    DebugLogic ("Creating new slot instance for slot-number: {0}", i);
                    // Then create new slot.
                    // TODO: Probably need internal methods for this
                    Slot tempslot = new Slot ();
                    tempslot.m_calendarState = CalendarState.FREE;
                    tempslot.m_slotNumber = i;
                    tempslot.m_reservationsForThisSlot = new List<Reservation> ();
                    tempslot.m_preCommitList = new SortedList<int, Reservation> ();
                    tempslot.m_lockedReservation = -1;

                    // Add to int-to-slot-object map
                    m_numberToSlotMap.Add (i, tempslot);
                }

                // Get the concerned slot
                Slot slot = m_numberToSlotMap[i];

                if (slot.m_calendarState == CalendarServiceClient.CalendarState.FREE ||
                    slot.m_calendarState == CalendarServiceClient.CalendarState.ACKNOWLEDGED)
                {
                    // Update the slot's reservation list
                    slot.m_reservationsForThisSlot.Add (reservation);

                    // Append to list of slots.
                    availableslots.Add (i);

                    // Update slot state
                    slot.m_calendarState = CalendarServiceClient.CalendarState.ACKNOWLEDGED;
                    DebugLogic ("Slot {0} is now in ACKNOWLEDGED state", i);
                }
            }

            // Respond with ACK/NACK
            if (availableslots.Count > 0)
            {
                // We do have at least one free slot, so respond with an ACK
                Message ack = new Message ();

                ack.SetSourceUserName (m_client.UserName);
                ack.SetDestinationUsers (src);
                ack.SetMessageType ("calendar");

                /*
                 * ACK Message format, data part
                 *
                 * - Number of Slots
                 * - Slot 1
                 * - Slot 2
                 * ...
                 * - Slot N
                 */
                availableslots.Reverse ();

                foreach (int i in availableslots)
                {
                    ack.PushString (i.ToString ());
                    DebugInfo ("Slot {0} is available", i);
                }

                ack.PushString (availableslots.Count.ToString ());
                ack.PushString (reservationSequenceNumber.ToString ());
                ack.PushString ("reservationack");

                DebugLogic ("Sending an ack to: {0}", src);

                SendMessage (ack);
                m_activeReservationSessions.Add (reservationSequenceNumber, reservation);
            }
            else
            {
                Message nack = new Message ();
                // No free slots, so respond with a NACK
                nack.SetSourceUserName (m_client.UserName);
                nack.SetDestinationUsers (src);
                nack.SetMessageType ("calendar");

                nack.PushString ("reservationnack");

                DebugLogic ("Sending a nack to: {0}", src);

                SendMessage (nack);
            }
        }
예제 #15
0
        private void ReceiveReservationPreCommit(Message m,
		                                          string src,
		                                          List<string> userlist,
		                                          int reservationSequenceNumber,
		                                          string messageSubType)
        {
            /* If I get a PRECOMMIT update for a slot,
             * and it is still in ACKNOWLEDGED state, then
             * respond with YES!. Else, respond with a NO!
             *
             * 		If I responded with a YES, then

             * 		move into PRECOMMIT state and begin
             * 		verification and commit timers.
             *
             * 			When verification timer fires, verify
             * 			your neighbours. TODO: Might need ping
             * 			utility
             *
             * 				If verification fails, ABORT, else do nothing.
             *
             * 			When commit timer fires, commit.
             *
             * 		If I responded with a NO, then move
             * 		into ABORT.
             *
             * 		If between any of the above, the coordinator
             * 		sends an ABORT message, then ABORT. DUH!
             */

            int s = Int32.Parse (m.PopString ());
            DebugLogic ("Received precommit for slot {0}, reservation number {1}",s,reservationSequenceNumber);

            Slot slot = m_numberToSlotMap[s];
            Reservation res = m_activeReservationSessions[reservationSequenceNumber];

            if (slot.m_calendarState == CalendarServiceClient.CalendarState.ACKNOWLEDGED
                || slot.m_calendarState == CalendarServiceClient.CalendarState.BOOKED)
            {

                if (slot.m_preCommitList.Count == 0 && slot.m_lockedReservation == -1)
                {
                    res.m_reservationState = CalendarServiceClient.ReservationState.TENTATIVELY_BOOKED;
                    slot.m_calendarState = CalendarServiceClient.CalendarState.BOOKED;
                    // No one has a lock, so this reservation gets it.
                    Message yes = new Message ();

                    yes.SetDestinationUsers (src);
                    yes.SetMessageType ("calendar");
                    yes.SetSourceUserName (m_client.UserName);
                    yes.PushString (s.ToString ());
                    yes.PushString (reservationSequenceNumber.ToString ());
                    yes.PushString ("yes");

                    slot.m_lockedReservation = reservationSequenceNumber;

                    SendMessage (yes);
                }
                else if (slot.m_lockedReservation != -1 && slot.m_lockedReservation < s)
                {
                    // Some reservation older is already locked, so wait.
                    slot.m_preCommitList.Add (reservationSequenceNumber, res);
                }
                else
                {
                    // Add older reservation to queue, we may upgrade or abort this
                    // depending on the result of the next step

                    slot.m_preCommitList.Add (reservationSequenceNumber, res);

                    // A newer reservation has been locked. For now,
                    // we try and ABORT the newer one in favour of the older one.
                    // But the optimisation here would be for coordinators to
                    // initiate an is-there-a-deadlock check, which the cohort
                    // would ask the coordinator to initiate.
                    Message abortmsg = new Message ();

                    abortmsg.SetDestinationUsers (m_activeReservationSessions[reservationSequenceNumber].m_initiator);
                    abortmsg.SetMessageType ("calendar");
                    abortmsg.SetSourceUserName (m_client.UserName);
                    abortmsg.PushString (s.ToString ()); // we need to mention the slot that is being aborted
                    abortmsg.PushString (slot.m_lockedReservation.ToString ());
                    abortmsg.PushString ("abort");

                    SendMessage (abortmsg);
                    ReservationAbortCohort (slot.m_lockedReservation, s);
                }
            }
        }
예제 #16
0
        private void ReceiveReservationDoCommit(Message m,
		                                          string src,
		                                          List<string> userlist,
		                                          int reservationSequenceNumber,
		                                          string messageSubType)
        {
            int s = Int32.Parse (m.PopString ());
            DebugLogic ("Received docommit for slot {0}, reservation number {1}",s,reservationSequenceNumber);

            Slot slot = m_numberToSlotMap[s];
            Reservation res = m_activeReservationSessions[reservationSequenceNumber];

            slot.m_calendarState = CalendarServiceClient.CalendarState.ASSIGNED;
            res.m_reservationState = CalendarServiceClient.ReservationState.COMMITTED;

            DebugLogic ("Reservation ID: {0}, Slot: {1} has COMMITTED", reservationSequenceNumber, s);

            if (m_client.m_isPuppetControlled)
            {
                m_client.m_puppetService.SendInfoMsgToPuppetMaster ("Reservation ID: {0}, Slot: {1} has COMMITTED",
                                                                    reservationSequenceNumber, s);
            }

            // Perform cleanup of all reservation objects
            foreach (int i in res.m_slotNumberList)
            {
                if (i != s)
                {
                    m_numberToSlotMap[i].m_reservationsForThisSlot.Remove (res);
                }
            }

            foreach (int i in slot.m_preCommitList.Keys)
            {

                Message abortmsg = new Message ();

                abortmsg.SetDestinationUsers (m_activeReservationSessions[reservationSequenceNumber].m_initiator);
                abortmsg.SetMessageType ("calendar");
                abortmsg.SetSourceUserName (m_client.UserName);
                abortmsg.PushString (s.ToString ()); // we need to mention the slot that is being aborted
                abortmsg.PushString (reservationSequenceNumber.ToString ());
                abortmsg.PushString ("abort");

                SendMessage (abortmsg);
                ReservationAbortCohort (i, s);
            }
        }
예제 #17
0
        public void Receive(ReceiveMessageEventArgs eventargs)
        {
            // parse message and call appropriate action
            Message m = eventargs.m_message;
            string message_source = m.GetSourceUserName ();
            string request_type = m.GetMessageType ();
            string message_source_uri = m.GetSourceUri ();

            if (request_type.Equals ("lookup"))
            {
                // Client has requested a username lookup,
                // respond with the URI string for the
                // user
                string user_request = m.PopString ();
                string uri = GetUriForUser (user_request);

                DebugInfo ("Answering lookup for {0} with {1}", user_request, uri);

                Message response = new Message ();
                response.SetMessageType ("lookup");
                response.SetDestinationUsers (message_source);
                response.SetSourceUserName (m_server.UserName);
                response.PushString (uri);
                SendReply(response);
            }
            else if (request_type.Equals ("connect"))
            {
                if (!m_server.m_replicationService.IsMaster)
                {
                    // TODO: reply, in future: redirect question?
                    DebugInfo ("Got request intended for master.");
                    m_server.m_replicationService.SendImNotMasterMessage (m);
                    return;
                }

                // add user to DB
                UserConnect (message_source, message_source_uri);

                // Send an ACK or the client starves to death
                Message ack_message = new Message ();
                ack_message.SetMessageType ("connect");
                ack_message.SetDestinationUsers (message_source);
                ack_message.SetSourceUserName (m_server.UserName);

                // replicate message (implicit block)
                m_server.m_replicationService.ReplicateUserConnect (message_source, message_source_uri);

                SendReply (ack_message);
            }
            else if (request_type.Equals ("disconnect"))
            {
                if (!m_server.m_replicationService.IsMaster)
                {
                    // TODO: reply, in future: redirect question?
                    DebugInfo ("Got request intended for master.");
                    m_server.m_replicationService.SendImNotMasterMessage (m);
                    return;
                }

                // remove from replicas (implicit block until 1 ack is received)
                m_server.m_replicationService.ReplicateUserDisconnect (message_source);

                UserDisconnect (message_source);

                // TODO: Find a way to get an ACK across
                // for a disconnect message
            }

            return;
        }
예제 #18
0
        public bool CommandClient(PuppetInstruction instruction)
        {
            if (!Clients.ContainsKey(instruction.ApplyToUser))
            {
                if (instruction.Type == PuppetInstructionType.CONNECT)
                {
                    if (instruction.ApplyToUser.Contains ("central"))
                    {
                        DebugLogic ("Starting new server: {0}", instruction.ApplyToUser);
                        SpawnServer(instruction.ApplyToUser);
                        // server will self-register, safe to return
                        return true;
                    }
                    else
                    {
                        DebugLogic ("Starting a new client: {0}", instruction.ApplyToUser);
                        SpawnClient (instruction.ApplyToUser);
                        // client will register with puppet master when initing, safe to return
                        return true;
                    }
                }

                DebugLogic ("No such user is connected: {0}", instruction.ApplyToUser);
                return false;
            }
            else if (instruction.Type == PuppetInstructionType.DISCONNECT
                     && instruction.ApplyToUser.Contains ("central"))
            {
                Clients.Remove (instruction.ApplyToUser);
                try
                {
                    SpawnedClients[instruction.ApplyToUser].Kill ();
                    SpawnedClients.Remove (instruction.ApplyToUser);
                    return true;
                }
                catch (InvalidOperationException)
                {
                    DebugLogic ("Couldn't kill server: {0}", instruction.ApplyToUser);
                }
            }

            Message m = new Message ();
            m.SetSourceUserName ("puppetmaster");
            m.SetDestinationUsers (instruction.ApplyToUser);
            m.SetMessageType ("puppetmaster");

            switch (instruction.Type)
            {
            case PuppetInstructionType.RESERVATION:
                m.PushString (BuildStringList (instruction.Slots));
                m.PushString (BuildStringList (instruction.Users));
                m.PushString (instruction.Description);
                m.PushString (instruction.Type.ToString ());
                break;
            default:
                m.PushString (instruction.Type.ToString ());
                break;
            }

            m_puppetMaster.m_sendReceiveMiddleLayer.Send (m);

            return true;
        }