Exemple #1
0
void ShutdownService::_sendShutdownRequestToService(const char* serviceName)
{
    MessageQueueService* _mqs = static_cast<MessageQueueService*>(_controller);

    MessageQueue *queue = MessageQueue::lookup(serviceName);
    Uint32 _queueId;
    if (queue)
    {
        _queueId =  queue->getQueueId();
    }
    else
    {
        // service not found, just return
        return;
    }
    // send a Stop (this is a legacy message that in some of the MQS does
    // termination of its internal stuff. Then follow it with a Stop (to
    // open up its incoming queue), and then with a AsyncIoClose
    // which closes the incoming queue.

    // All of these messages MUST be sequential. Do not use SendForget or
    // SendAsync as those are asynchronous and their receipt is guaranteed
    // to be undeterministic and possibly out of sequence (which is something
    // we do not want).

    CimServiceStop stop_message(
        NULL,
        _queueId,
        _controller->getQueueId(),
        true);

    AutoPtr<AsyncReply> StopAsyncReply(
        _controller->ClientSendWait(_queueId, &stop_message));

    CimServiceStart start_message(
        NULL,
        _queueId,
        _controller->getQueueId(),
        true);

    AutoPtr <AsyncReply> StartAsyncReply(
        _controller->ClientSendWait(_queueId, &start_message));

    AsyncIoClose close_request(
        NULL,
        _queueId,
        _controller->getQueueId(),
        false);

    AutoPtr <AsyncReply> CloseAsyncReply(
        _controller->ClientSendWait(_queueId, &close_request));
}
Exemple #2
0
void HTTPAuthenticatorDelegator::_sendResponse(
    Uint32 queueId,
    Buffer& message,
    Boolean closeConnect)
{
    PEG_METHOD_ENTER(TRC_HTTP,
        "HTTPAuthenticatorDelegator::_sendResponse");

    MessageQueue* queue = MessageQueue::lookup(queueId);

    if (queue)
    {
        AutoPtr<HTTPMessage> httpMessage(new HTTPMessage(message));
        httpMessage->dest = queue->getQueueId();
        
        queue->enqueue(httpMessage.release());
    }

    PEG_METHOD_EXIT();
}
bool RebalanceImpl::updateProcessQueueTableInRebalance(const std::string& topic, std::set<MessageQueue>& mqSet)
{
	bool changed = false;

	// 将多余的队列删除
	std::map<MessageQueue, ProcessQueue*>::iterator it = m_processQueueTable.begin();

	for ( ; it != m_processQueueTable.end();)
	{
		MessageQueue mq = it->first;
		if (mq.getTopic() == topic)
		{
			std::set<MessageQueue>::iterator its = mqSet.find(mq);
			if (its == mqSet.end())
			{
				changed = true;
				ProcessQueue* pq = it->second;
				if (pq != NULL)
				{
					pq->setDroped(true);
					removeUnnecessaryMessageQueue(mq, *pq);
					//TODO log.info("doRebalance, {}, remove unnecessary mq, {}",
					//	consumerGroup, mq);
				}
				std::map<MessageQueue, ProcessQueue*>::iterator ittmp = it;
				it++;
				m_processQueueTable.erase(ittmp);
			}
			else
			{
				it++;
			}
		}
		else
		{
			it++;
		}
	}

	// 增加新增的队列
	std::list<PullRequest> pullRequestList;

	std::set<MessageQueue>::iterator its = mqSet.begin();
	for (; its != mqSet.end(); its++)
	{
		MessageQueue mq = *its;
		std::map<MessageQueue, ProcessQueue*>::iterator itm = m_processQueueTable.find(mq);

		if (itm == m_processQueueTable.end())
		{
			PullRequest pullRequest;
			pullRequest.setConsumerGroup(m_consumerGroup);
			pullRequest.setMessageQueue(new MessageQueue(mq.getTopic(),mq.getBrokerName(),mq.getQueueId()));
			pullRequest.setProcessQueue(new ProcessQueue());

			// 这个需要根据策略来设置
			long long nextOffset = computePullFromWhere(mq);
			if (nextOffset >= 0)
			{
				pullRequest.setNextOffset(nextOffset);
				pullRequestList.push_back(pullRequest);
				changed = true;
				m_processQueueTable[mq] = pullRequest.getProcessQueue();
				//TODO log.info("doRebalance, {}, add a new mq, {}", consumerGroup, mq);
			}
			else
			{
				// 等待此次Rebalance做重试
				//TODO log.warn("doRebalance, {}, add new mq failed, {}", consumerGroup, mq);
			}
		}
	}

	dispatchPullRequest(pullRequestList);

	return changed;
}
void DefaultPropertyOwner::_requestIndicationServiceStateChange(
    const String& userName,
    Boolean enable,
    Uint32 timeoutSeconds)
{
    MessageQueue *queue = MessageQueue::lookup(
        PEGASUS_QUEUENAME_INDICATIONSERVICE);
    // Return if indication service can not be found
    if (!queue)
    {
        return;
    }

    Uint32 queueId = queue->getQueueId();

    const String METHOD_NAME = "RequestStateChange";
    const String PARAMNAME_REQUESTEDSTATE = "RequestedState";
    const String PARAMNAME_TIMEOUTPERIOD = "TimeoutPeriod";
    const Uint16 STATE_ENABLED = 2;
    const Uint16 STATE_DISABLED = 3;

    String referenceStr("//", 2);
    referenceStr.append(System::getHostName());
    referenceStr.append("/");
    referenceStr.append(PEGASUS_NAMESPACENAME_INTEROP.getString());
    referenceStr.append(":");
    referenceStr.append(
        PEGASUS_CLASSNAME_CIM_INDICATIONSERVICE.getString());
    CIMObjectPath reference(referenceStr);

    Array<CIMParamValue> inParams;
    Array<CIMParamValue> outParams;

    inParams.append(CIMParamValue(PARAMNAME_REQUESTEDSTATE,
        CIMValue(enable ? STATE_ENABLED : STATE_DISABLED)));

    inParams.append(CIMParamValue(PARAMNAME_TIMEOUTPERIOD,
        CIMValue(CIMDateTime(timeoutSeconds * 1000000, true))));

    MessageQueueService *controller = ModuleController::getModuleController();

    try
    {
        CIMInvokeMethodRequestMessage* request =
            new CIMInvokeMethodRequestMessage(
                XmlWriter::getNextMessageId(),
                PEGASUS_NAMESPACENAME_INTEROP,
                referenceStr,
                CIMNameCast(METHOD_NAME),
                inParams,
                QueueIdStack(queueId));

        request->operationContext.insert(
            IdentityContainer(userName));

        AsyncLegacyOperationStart *asyncRequest =
            new AsyncLegacyOperationStart(
                0,
                queueId,
                request);

        AsyncReply * asyncReply = controller->SendWait(asyncRequest);

        CIMInvokeMethodResponseMessage * response =
            reinterpret_cast<CIMInvokeMethodResponseMessage *>(
                (static_cast<AsyncLegacyOperationResult *>(
                    asyncReply))->get_result());

        CIMException e = response->cimException;

        delete response;
        delete asyncRequest;
        delete asyncReply;

        if (e.getCode() != CIM_ERR_SUCCESS)
        {
            throw e;
        }
    }
    catch(const Exception &e)
    {
        PEG_TRACE((TRC_CONFIG,Tracer::LEVEL1,
            "Exception caught while invoking CIM_IndicationService."
                "RequestStateChange()  method: %s",
        (const char*)e.getMessage().getCString()));
        throw;
    }
    catch(...)
    {
        PEG_TRACE_CSTRING(TRC_CONFIG,Tracer::LEVEL1,
            "Unknown exception caught while invoking CIM_IndicationService."
                "RequestStateChange()  method");
        throw;
    }
}
Exemple #5
0
void HTTPAuthenticatorDelegator::handleHTTPMessage(
    HTTPMessage* httpMessage,
    Boolean & deleteMessage)
{  
    PEG_METHOD_ENTER(TRC_HTTP,
        "HTTPAuthenticatorDelegator::handleHTTPMessage");

    Boolean authenticated = false;
    deleteMessage = true;

    // ATTN-RK-P3-20020408: This check probably shouldn't be necessary, but
    // we're getting an empty message when the client closes the connection
    if (httpMessage->message.size() == 0)
    {
        // The message is empty; just drop it
        PEG_METHOD_EXIT();
        return;
    }

    //
    // get the configured authentication flag
    //
    // WMI MAPPER SPECIFIC: AUTHENTICATION ALWAYS ENABLED:
    Boolean enableAuthentication = true;
    /* NORMAL METHOD OF LOOKING UP AUTHENTICATION CONFIGURATION:
    Boolean enableAuthentication = ConfigManager::parseBooleanValue(
        ConfigManager::getInstance()->getCurrentValue("enableAuthentication"));
    */

    //
    // Save queueId:
    //
    Uint32 queueId = httpMessage->queueId;

    //
    // Parse the HTTP message:
    //
    String startLine;
    Array<HTTPHeader> headers;
    Uint32 contentLength;

    httpMessage->parse(startLine, headers, contentLength);
    
    //
    // Parse the request line:
    //
    String methodName;
    String requestUri;
    String httpVersion;
    HttpMethod httpMethod = HTTP_METHOD__POST;

    HTTPMessage::parseRequestLine(
        startLine, methodName, requestUri, httpVersion);

    //
    //  Set HTTP method for the request
    //
    if (methodName == "M-POST")
    {
        httpMethod = HTTP_METHOD_M_POST;
    }

    if (methodName != "M-POST" && methodName != "POST")
    {
        // Only POST and M-POST are implemented by this server
        _sendHttpError(queueId,
                       HTTP_STATUS_NOTIMPLEMENTED);
    }
    else if ((httpMethod == HTTP_METHOD_M_POST) &&
             (httpVersion == "HTTP/1.0"))
    {
        //
        //  M-POST method is not valid with version 1.0
        //
        _sendHttpError(queueId,
                       HTTP_STATUS_BADREQUEST);
    }
    else
    {
        //
        // Process M-POST and POST messages:
        //
        PEG_TRACE_CSTRING(
            TRC_HTTP,
            Tracer::LEVEL3,
            "HTTPAuthenticatorDelegator - M-POST/POST processing start");

        //
        // Search for Authorization header:
        //
        String authorization;

        //
        // Do not require authentication for indication delivery 
        //
        String cimExport;
        if (enableAuthentication &&
            HTTPMessage::lookupHeader(
                headers, "CIMExport", cimExport, true)) 
        {
            enableAuthentication = false;
        }

        if ( HTTPMessage::lookupHeader(
             headers, "PegasusAuthorization", authorization, false) &&
             enableAuthentication
           )
        {
            try 
            {
                //
                // Do pegasus/local authentication
                //
                authenticated = 
                    _authenticationManager->performPegasusAuthentication(
                        authorization,
                        httpMessage->authInfo);

                if (!authenticated)
                {
                    String authChallenge;
                    String authResp;

                    authResp =
                        _authenticationManager->getPegasusAuthResponseHeader(
                            authorization,
                            httpMessage->authInfo);

                    if (!String::equal(authResp, String::EMPTY))
                    {
                        _sendChallenge(queueId, authResp, false);
                    }
                    else
                    {
                        _sendHttpError(queueId,
                                       HTTP_STATUS_BADREQUEST,
                                       String::EMPTY,
                                       "Authorization header error");
                    }

                    PEG_METHOD_EXIT();
                    return;
                }
            }
            catch (CannotOpenFile &cof)
            {
                _sendHttpError(queueId,
                               HTTP_STATUS_INTERNALSERVERERROR);
                PEG_METHOD_EXIT();
                return;
                
            }
        }

        if ( HTTPMessage::lookupHeader(
             headers, "Authorization", authorization, false) &&
             enableAuthentication
           )
        {
#ifdef PEGASUS_KERBEROS_AUTHENTICATION
            // The presence of a Security Association indicates that Kerberos
            // is being used.
            CIMKerberosSecurityAssociation *sa =
                httpMessage->authInfo->getSecurityAssociation();
            if (sa)
            {
                sa->setClientSentAuthorization(true);
            }
#endif        
            //
            // Do http authentication if not authenticated already
            //
            if (!authenticated)
            {
                authenticated =
                    _authenticationManager->performHttpAuthentication(
                        authorization,
                        httpMessage->authInfo);

                if (!authenticated)
                {
                    //ATTN: the number of challenges get sent for a 
                    //      request on a connection can be pre-set.
#ifdef PEGASUS_KERBEROS_AUTHENTICATION
                    // Kerberos authentication needs access to the
                    // AuthenticationInfo object for this session in order
                    // to set up the reference to the
                    // CIMKerberosSecurityAssociation object for this session.

                    String authResp =   
                        _authenticationManager->getHttpAuthResponseHeader(
                            httpMessage->authInfo);
#else
                    String authResp =
                        _authenticationManager->getHttpAuthResponseHeader();
#endif
                    if (!String::equal(authResp, String::EMPTY))
                    {
                        _sendChallenge(queueId, authResp, false);
                    }
                    else
                    {
                        _sendHttpError(queueId,
                                       HTTP_STATUS_BADREQUEST,
                                       String::EMPTY,
                                       "Authorization header error");
                    }

                    PEG_METHOD_EXIT();
                    return;
                }
            }  // first not authenticated check
        }  // "Authorization" header check

#ifdef PEGASUS_KERBEROS_AUTHENTICATION
        // The presence of a Security Association indicates that Kerberos is
        // being used.
        CIMKerberosSecurityAssociation *sa =
            httpMessage->authInfo->getSecurityAssociation();

        // This will process a request with no content.
        if (sa && authenticated)
        {
            if (sa->getServerToken().size())
            {
                // This will handle the scenario where client did not send
                // data (content) but is authenticated.  After the client
                // receives the success it should will send the request.
                // For mutual authentication the client may choose not to
                // send request data until the context is fully established.
                // Note:  if mutual authentication wass not requested by the
                // client then no server token will be available.
                if (contentLength == 0)
                {
                    String authResp =   
                        _authenticationManager->getHttpAuthResponseHeader(
                            httpMessage->authInfo);
                    if (!String::equal(authResp, String::EMPTY))
                    {
                        _sendSuccess(queueId, authResp);
                    }
                    else
                    {
                        _sendHttpError(queueId,
                                       HTTP_STATUS_BADREQUEST,
                                       String::EMPTY,
                                       "Authorization header error");
                    }

                    PEG_METHOD_EXIT();
                    return;
                }
            }
        }

        // This will process a request without an authorization record.
        if (sa && !authenticated)
        {
            // Not authenticated can result from the client not sending an
            // authorization record due to a previous authentication.  In
            // this scenario the client was previous authenticated but
            // chose not to send an authorization record.  The Security
            // Association maintains state so a request will not be
            // processed unless the Security association thinks the client
            // is authenticated.

            // This will handle the scenario where the client was
            // authenticated in the previous request but choose not to
            // send an authorization record.
            if (sa->getClientAuthenticated())
            {        
                authenticated = true;
            }
        }

        // The following is processing to unwrap (unencrypt) the message
        // received from the client when using kerberos authentication.
        // For Kerberos there should always be an "Authorization" record
        // sent with the request so the authenticated flag in the method
        // should always be checked to verify that the client is actually
        // authenticated.  If no "Authoriztion" was sent then the client
        // can't be authenticated.  The "Authorization" record was
        // processed above and if the "Authorization" record was
        // successfully processed then the client is authenticated.
        if (sa  &&  authenticated)
        {
            Uint32 rc;  // return code for the wrap
            Array<Sint8> final_buffer;
            final_buffer.clear();
            Array<Sint8> header_buffer;
            header_buffer.clear();
            Array<Sint8> inWrappedMessage;
            inWrappedMessage.clear();
            Array<Sint8> outUnwrappedMessage;
            outUnwrappedMessage.clear();

            // The message needs to be parsed in order to distinguish
            // between the headers and content. The message was parsed
            // earlier in this method so we can use the contentLength set
            // during that parse. When parsing the code breaks out of the
            // loop as soon as it finds the double separator that
            // terminates the headers so the headers and content can be
            // easily separated.

            // Extract the unwrapped headers
            for (Uint32 i = 0; i < httpMessage->message.size() - contentLength;
                 i++)
            {
                header_buffer.append(httpMessage->message[i]);
            }

            // Extract the wrapped content
            for (Uint32 i = httpMessage->message.size() - contentLength;
                 i < httpMessage->message.size(); i++)
            {
                inWrappedMessage.append(httpMessage->message[i]);
            }

            rc = sa->unwrap_message(inWrappedMessage,          
                                    outUnwrappedMessage);  // ASCII

            if (rc) 
            {
                // clear out the outUnwrappedMessage; if unwrapping is required
                // and it fails we need to send back a bad request.  A message
                // left in an wrapped state will be a severe failue later.  
                // Reason for unwrap failing may be due to a problem with the 
                // credentials or context or some other failure may have 
                // occurred.
                outUnwrappedMessage.clear();
                // build a bad request.  We do not want to risk sending back
                // data that can't be authenticated.
                final_buffer = 
                  XmlWriter::formatHttpErrorRspMessage(HTTP_STATUS_BADREQUEST);
                //remove the last separater; the authentication record still
                // needs to be added.
                final_buffer.remove(final_buffer.size());  // "\n"
                final_buffer.remove(final_buffer.size());  // "\r"

                // Build the WWW_Authenticate record with token.
                String authResp =   
                  _authenticationManager->getHttpAuthResponseHeader(
                                httpMessage->authInfo);
                // error occurred on wrap so the final_buffer needs to be built
                // differently
                final_buffer << authResp;
                // add double separaters to end
                final_buffer << "\r\n";
                final_buffer << "\r\n";

                _sendResponse(queueId, final_buffer);
                PEG_METHOD_EXIT();
                return;
            }

            // If outUnwrappedMessage does not have any content data this
            // is a result of no data available.  This could be a result
            // of the client not sending any content data.  This is not
            // unique to Kerberos so this will not be handled here but it
            // will be handled when the content is processed. Or, the
            // client did not wrap message...this is okay.  If the unwrap
            // resulted in no data when there should have been data then
            // this should have been caught above when the unwrap returned
            // a bad return code
            if (final_buffer.size() == 0)
            {
                // if outUnwrappedMessage is empty that indicates client did 
                // not wrap the message.  The original message will be used.
                if (outUnwrappedMessage.size())
                {
                    final_buffer.appendArray(header_buffer);
                    final_buffer.appendArray(outUnwrappedMessage);
                    // add back char that was appended earlier
                    final_buffer.append('\0'); 
                    // Note: if additional characters added 
                    // in future add back here
                }
            }
            else
            {
                // The final buffer should not have any data at this point.
                // If it does end the server because something bad happened.
                PEG_TRACE_CSTRING(
                    TRC_HTTP,
                    Tracer::LEVEL2,
                    "HTTPAuthenticatorDelegator - the final buffer should "
                        "not have data");
                PEGASUS_ASSERT(0);
            }

            // replace the existing httpMessage with the headers and
            // unwrapped message
            // If the final buffer has not been set then the original
            // httpMessage will be used.
            if (final_buffer.size())
            {
                    httpMessage->message.clear();
                    httpMessage->message = final_buffer;
            }
        } // if not kerberos and client not authenticated
#endif

        if ( authenticated || !enableAuthentication )
        {
            //
            // Search for "CIMOperation" header:
            //
            String cimOperation;

            if (HTTPMessage::lookupHeader(
                headers, "CIMOperation", cimOperation, true))
            {
                PEG_TRACE((
                    TRC_HTTP,
                    Tracer::LEVEL3,
                    "HTTPAuthenticatorDelegator - CIMOperation: %s ",
                    (const char*) cimOperation.getCString()));

                MessageQueue* queue =
                    MessageQueue::lookup(_cimOperationMessageQueueId);

                if (queue)
                {
                   httpMessage->dest = queue->getQueueId();
                   
                   try
                     {
                       queue->enqueue(httpMessage);
                     }
                   catch(exception & e)
                     {
                       delete httpMessage;
                       _sendHttpError(queueId,
                                      HTTP_STATUS_REQUEST_TOO_LARGE);
                       PEG_METHOD_EXIT();
                       deleteMessage = false;
                       return;
                     }
                 deleteMessage = false;
                }
            }
            else if (HTTPMessage::lookupHeader(
                headers, "CIMExport", cimOperation, true))
            {
                PEG_TRACE((
                    TRC_HTTP,
                    Tracer::LEVEL3,
                    "HTTPAuthenticatorDelegator - CIMExport: $0 ",
                    (const char*) cimOperation.getCString()));

                MessageQueue* queue =
                    MessageQueue::lookup(_cimExportMessageQueueId);

                if (queue)
                {
                    httpMessage->dest = queue->getQueueId();

                    queue->enqueue(httpMessage);
                    deleteMessage = false;
                }
            }
            else
            {
                // We don't recognize this request message type

                // The Specification for CIM Operations over HTTP reads:
                //
                //     3.3.4. CIMOperation
                //
                //     If a CIM Server receives a CIM Operation request without
                //     this [CIMOperation] header, it MUST NOT process it as if
                //     it were a CIM Operation Request.  The status code
                //     returned by the CIM Server in response to such a request
                //     is outside of the scope of this specification.
                //
                //     3.3.5. CIMExport
                //
                //     If a CIM Listener receives a CIM Export request without
                //     this [CIMExport] header, it MUST NOT process it.  The
                //     status code returned by the CIM Listener in response to
                //     such a request is outside of the scope of this
                //     specification.
                //
                // The author has chosen to send a 400 Bad Request error, but
                // without the CIMError header since this request must not be
                // processed as a CIM request.

                _sendHttpError(queueId,
                               HTTP_STATUS_BADREQUEST);
                PEG_METHOD_EXIT();
                return;
            } // bad request
        } // authenticated and enableAuthentication check
        else
        {  // client not authenticated; send challenge
#ifdef PEGASUS_KERBEROS_AUTHENTICATION
            String authResp =    
                _authenticationManager->getHttpAuthResponseHeader(
                    httpMessage->authInfo);
#else
            String authResp =
                _authenticationManager->getHttpAuthResponseHeader();
#endif

            if (!String::equal(authResp, String::EMPTY))
            {
                _sendChallenge(queueId, authResp, false);
            }
            else
            {
                _sendHttpError(queueId,
                               HTTP_STATUS_BADREQUEST,
                               String::EMPTY,
                               "Authorization header error");
            }
        }
    } // M-POST and POST processing

    PEG_METHOD_EXIT();
}
ThreadReturnType PEGASUS_THREAD_CDECL
client_func (void *parm)
{
    Thread *myself = reinterpret_cast < Thread * >(parm);

    test_async_queue *client = new test_async_queue (test_async_queue::CLIENT);

    // find the server 
    MessageQueue *serverQueue = 0;
    while (serverQueue == 0)
    {
        serverQueue = MessageQueue::lookup("server");
        // It is a good idea to yield to other threads. You should do this,
        // but this test-case stresses situations in which does not happen.
        //Threads::yield ();
    }

    if (verbose)
    {
        cout << "testing low-level async send " << endl;
    }

    Uint32 requestCount = 0;
    while (requestCount < 10000)
    {
        // The problem on multi-processor machines is that if we make it
        // continue on sending the messages, and the MessageQueueService
        // does not get to pick up the messages, the machine can crawl to
        // halt with about 300-400 threads and ever-continuing number of
        // them created. This is an evil stress test so lets leave it behind.
        try
        {
            Message *cim_rq = new Message (CIM_GET_INSTANCE_REQUEST_MESSAGE);

            AsyncOpNode *op = client->get_op();
            AsyncOperationStart *async_rq =
                new AsyncOperationStart(
                    op,
                    serverQueue->getQueueId(),
                    client->getQueueId(),
                    false,
                    cim_rq);
            client->SendAsync(
                op,
                serverQueue->getQueueId(),
                test_async_queue::async_handleEnqueue,
                client,
                (void *) 0);
        }
        catch (const PEGASUS_STD(bad_alloc) &)
        {
            cerr << "Out of memory! Continuing tests." << endl;
            continue;
        }
        requestCount++;

        // You really ought to allow other threads to their job (like picking
        // up all of these messages, but we want to stress test unfair
        // circumstances. 
        //Threads::yield ();
    }

    if (verbose)
    {
        cout << "Waiting until all messages are flushed." << endl;
    }
    while (test_async_queue::msg_count.get() != requestCount)
    {
        if (verbose)
        {
            if (test_async_queue::msg_count.get() % (requestCount/10) == 0)
            {
                cout << test_async_queue::msg_count.get() / (requestCount/100)
                    << "% complete" << endl;
            }
        }
        Threads::yield();
    }

    if (verbose)
    {
        cout << "Waiting until all messages are flushed. " << endl;
    }
    while (test_async_queue::msg_count.get() != requestCount)
    {
        if (verbose)
        {
            if (test_async_queue::msg_count.get() % (requestCount/10) == 0)
            {
                cout << test_async_queue::msg_count.get() / (requestCount/100)
                    << "% complete" << endl;
            }
        }
        Threads::yield();
    }

    if (verbose)
    {
        cout << "sending stop to server " << endl;
    }
    try
    {
        CimServiceStop *stop = new CimServiceStop(
            0,
            serverQueue->getQueueId(),
            client->getQueueId (),
            true);

        AsyncMessage *reply = client->SendWait (stop);
        delete stop;
        delete reply;
    }
    catch (const PEGASUS_STD(bad_alloc) &)
    {
        cerr <<" Out of memory! Continuing tests." << endl;
    }

    // wait for the server to shut down 
    while (serverQueue)
    {
        serverQueue = MessageQueue::lookup("server");
        Threads::yield ();
    }

    if (verbose)
    {
        cout << "shutting down client" << endl;
    }

    delete client;
    return ThreadReturnType(0);
}