BUG#: 8605
authorharsha.bm <harsha.bm>
Fri, 9 Oct 2009 05:31:06 +0000 (05:31 +0000)
committerharsha.bm <harsha.bm>
Fri, 9 Oct 2009 05:31:06 +0000 (05:31 +0000)
TITLE: CIM operation fails after idle connection timeout due to server closing the connection.
DESCRIPTION: updated CIMClientRep to check connection status for every request and reconnect in the event of idle timeout.

src/Pegasus/Client/CIMClientRep.cpp
src/Pegasus/Client/CIMOperationResponseDecoder.cpp
src/Pegasus/Client/tests/IdleConnectionTimeout/IdleConnectionTimeout.cpp
src/Pegasus/Common/HTTPConnection.cpp
src/Pegasus/Common/HTTPConnection.h

index 6d79fb42d22b8a0692636b06c59a5ca0af51e318..a13d57e2e86afb44b9aab0141d3b0e3ca33e2f77 100644 (file)
@@ -1151,6 +1151,13 @@ Message* CIMClientRep::_doRequest(
         throw NotConnectedException();
     }
 
+    // Check if the connection has to be re-established
+    if (_httpConnection->needsReconnect())
+    {
+        _disconnect();
+        _doReconnect = true;
+    }
+
     if (_doReconnect)
     {
         _connect(_binaryRequest, _binaryResponse);
index 77f96e99440a21b8ff9fe23566c60ae1b8feb107..b530f78131cce44148932f123c94989401747175 100644 (file)
@@ -126,6 +126,9 @@ void CIMOperationResponseDecoder::_handleHTTPMessage(HTTPMessage* httpMessage)
         ClientExceptionMessage * response =
             new ClientExceptionMessage(malformedHTTPException);
 
+       //reconnect and resend next request
+        response->setCloseConnect(true);
+
         _outputQueue->enqueue(response);
         return;
     }
index c24e24068bdebc6b0a40512fc932d873811a2a1f..21b3a9f4c87f982805272ca968bb623050711119 100644 (file)
@@ -96,13 +96,8 @@ ThreadReturnType PEGASUS_THREAD_CDECL _runningThd(void *parm)
         }
         catch(Exception& e)
         {
-            // Ignore idle timeout -- may happen on slow or loaded systems.
-            if (!String::equal(
-                e.getMessage(),"Connection closed by CIM Server."))
-            {
-                cerr << "Error: " << e.getMessage() << endl;
-                throw;
-            }
+            cerr << "Error: " << e.getMessage() << endl;
+            throw;
         }
 
         client.disconnect();
@@ -143,21 +138,15 @@ ThreadReturnType PEGASUS_THREAD_CDECL _idleThd(void *parm)
         {
             Threads::sleep(1000);
         }
-
+        //the client shall reconnect if the connection was closed and 
+        //so the operation should succeed.
         CIMClass tmpClass2 =
             client.getClass (OSINFO_NAMESPACE, OSINFO_CLASSNAME);
     }
     catch(Exception& e)
     {
-        if (String::equal(e.getMessage(),"Connection closed by CIM Server."))
-        {
-            test2CaughtException = true;
-            cout << "Expected error: " << e.getMessage() << endl;
-        }
-        else
-        {
-            cerr << "Error: " << e.getMessage() << endl;
-        }
+        test2CaughtException = true;
+        cerr << "Error: " << e.getMessage() << endl;
     }
     client.disconnect();
 
@@ -222,12 +211,12 @@ Boolean _test1(
     return TEST_PASSED;
 }
 
-// _test2 verifies that a CIM Operation on a client connection does not
+// _test2 verifies that a CIM Operation on a client connection will still
 // succeed when the idleConnectionTimeout period is exceeded (_idleThd) *and*
 // there is concurrent server activity (_runningThd) so that the Monitor
-// will wake up and check for timeouts. In this case, the second call to
-// getClass() in _idleThd() should receive an exception because the
-// connection has been closed due to the timeout.
+// will wake up and check for timeouts and close the connection.
+// In this case, the second call to getClass() in _idleThd() will reconnect 
+// and send the request.
 Boolean _test2(
     int durationSeconds, const char * testUserid, const char * testPasswd)
 {
@@ -266,9 +255,8 @@ Boolean _test2(
         return TEST_FAILED;
     }
 
-    // We except the exception in this case, so if it was caught
-    // then the test passed.
-    return test2CaughtException;
+    // We do not expect exception in this case.
+    return (test2CaughtException == false);
 }
 
 int main(int argc, char** argv)
index 01cf262c716f2e281c6b317f1180db497dbdced2..d26bda8bf84cbc7c89d8ddec7147b7cf15fcf7be 100644 (file)
@@ -214,6 +214,28 @@ Uint32 HTTPConnection::getIdleConnectionTimeout()
     return _idleConnectionTimeoutSeconds;
 }
 
+/*
+    Note: This method is called in client code for reconnecting with the Server 
+    and can also be used in the server code to check the connection status  and 
+    take appropriate actions.it checks whether the connection is alive by 
+    attempting to read 1 byte from the socket.This method MUST not be used when 
+    incoming data is expected from the connection.
+
+    Returns TRUE when there is no data and peer has closed the connection
+    gracefully or there is an unanticipated incoming data, returns FALSE
+    otherwise. Note that this method does not consider the errors returned
+    from read().
+*/
+
+Boolean HTTPConnection::needsReconnect()
+{
+    char buffer;
+
+    int n =  _socket->read(&buffer, sizeof(buffer));
+    
+    return n >= 0;
+}
+
 HTTPConnection::HTTPConnection(
     Monitor* monitor,
     SharedPtr<MP_Socket>& socket,
index b6550dbfc98cebd0b093676564790370022d5ad4..0d471fc2eef5e89ec754c557bdb1cdbf758d8f00 100644 (file)
@@ -104,6 +104,11 @@ public:
 
     Boolean closeConnectionOnTimeout(struct timeval* timeNow);
 
+    // This method is called in Client code to decide reconnection with 
+    // the Server and can also be used in the server code to check if the 
+    // connection is still alive and take appropriate action.
+    Boolean needsReconnect();
+
     // This method is called in Server code when response encoders or
     // HTTPAuthenticatorDelegator runs out-of-memory. This method calls 
     // _handleWriteEvent() with a dummy HTTPMessage to maintain  response