RoleChanger bugs fixed:
1) Disconnect switch if no role-reply received from switch that supports role messages
2) Turn off pendingRole boolean when role-reply or error-msg is received

Change-Id: I4a5cfc5e99b85001192e5ac0e45202daac09bfa9
diff --git a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
index a79e7d9..2008697 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/OFChannelHandler.java
@@ -421,11 +421,11 @@
             }
 
             if (pendingRole == role) {
+                requestPending = false; // we got what we were waiting for
                 log.debug("Received role reply message from {} that matched "
                         + "expected role-reply {} with expectations {}",
                         new Object[] {getSwitchInfoString(), role, expectation});
                 counters.roleReplyReceived.updateCounterWithFlush();
-                //setSwitchRole(role, RoleRecvStatus.RECEIVED_REPLY); dont want to set state here
                 if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
                         expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
                     return expectation;
@@ -435,9 +435,16 @@
             }
 
             // if xids match but role's don't, perhaps its a query (OF1.3)
-            if (expectation == RoleRecvStatus.REPLY_QUERY)
+            if (expectation == RoleRecvStatus.REPLY_QUERY) {
+                requestPending = false; // again we got what we were waiting for
                 return expectation;
+            }
 
+            // It is not clear what this role-reply was about, since it is not
+            // a query and it did not match the pendingRole. But since the xid's
+            // matched, we state that we received what we were waiting for, and
+            // let the caller handle it
+            requestPending = false;
             return RoleRecvStatus.OTHER_EXPECTATION;
         }
 
@@ -467,6 +474,7 @@
                 return RoleRecvStatus.OTHER_EXPECTATION;
             }
             // it is an error related to a currently pending role request message
+            requestPending = false; // we got a response, even though it is an error
             if (error.getErrType() == OFErrorType.BAD_REQUEST) {
                 counters.roleReplyErrorUnsupported.updateCounterWithFlush();
                 log.error("Received a error msg {} from sw {} in state {} for "
@@ -513,10 +521,13 @@
 
         /**
          * Check if a pending role request has timed out.
+         *
+         * @throws SwitchStateException
          */
-        void checkTimeout() {
-            if (!requestPending)
+        void checkTimeout() throws SwitchStateException {
+            if (!requestPending) {
                 return;
+            }
             synchronized(this) {
                 if (!requestPending)
                     return;
@@ -524,8 +535,7 @@
                 if (now - roleSubmitTime > roleTimeoutMs) {
                     // timeout triggered.
                     counters.roleReplyTimeout.updateCounterWithFlush();
-                    //setSwitchRole(pendingRole, RoleRecvStatus.NO_REPLY);
-                    // XXX S come back to this
+                    state.handleTimedOutRoleReply(OFChannelHandler.this, pendingRole);
                 }
             }
         }
@@ -1824,6 +1834,25 @@
 			RoleRecvStatus expectation) throws IOException {
 		// do nothing in most states
         }
+
+        /**
+         * Handles role request messages that have timed out.
+         * <p>
+         * Role request messages that don't get role-replies (or errors related
+         * to the request) time out after DEFAULT_ROLE_TIMEOUT_MS secs, at which
+         * time the controller state-machine disconnects the switch
+         *
+         * @param h the channel handler for this switch
+         * @param pendingRole the role for which no reply was received
+         * @throws SwitchStateException
+         */
+        public void handleTimedOutRoleReply(OFChannelHandler h,
+                Role pendingRole) throws SwitchStateException {
+            String msg = String.format("Switch: [%s] State: [%s] did not "
+                    + "reply to role-msg for pending role %s. Disconnecting ...",
+                    h.getSwitchInfoString(), this.toString(), pendingRole);
+            throw new SwitchStateException(msg);
+        }
     }