int MulticastClientTransport::send(
        I_ClientTransportCallback &clientStub,
        const std::vector<ByteBuffer> &data,
        unsigned int timeoutMs)
    {
        // TODO: in some cases, may need to make a full copy of data for 
        // each individual sub-transport, as they might transform the data.

        bringInNewTransports();

        Lock lock(mClientTransportsMutex);

        // TODO: hardcoded
        timeoutMs = 1000;
        bool needToRemove = false;

        ClientTransportList::iterator iter;
        for (
            iter = mClientTransports.begin();
            iter != mClientTransports.end();
            ++iter)
        {
            try
            {
                if ((**iter)->isInProcess())
                {
                    ClientStub & stub = static_cast<ClientStub &>(clientStub);
                    (**iter)->doInProcessCall(stub);
                }
                else
                {
                    // We used to check *iter->isConnected() here, and if so not
                    // try the send at all. Appear to have been synchronization 
                    // issues when doing that though.

                    // Sending synchronously, so no use for the callback
                    DummyCallback dummyCallback;
                    (**iter)->send(dummyCallback, data, timeoutMs);
                }
            }
            catch(const Exception &e)
            {
                RCF_LOG_1()(e) << "Error publishing to subscriber.";
                needToRemove = true;
                iter->reset();
            }
        }

        if (needToRemove)
        {
            mClientTransports.remove( ClientTransportAutoPtrPtr() );
        }       

        clientStub.onSendCompleted();

        return 1;
    }
    void MulticastClientTransport::dropIdleTransports()
    {
        bringInNewTransports();

        Lock lock(mClientTransportsMutex);

        bool needToRemove = false;

        ClientTransportList::iterator iter;
        for (iter = mClientTransports.begin(); iter != mClientTransports.end(); ++iter)
        {
            RCF::ClientTransport & transport = ***iter;
            RcfSessionWeakPtr rcfSessionWeakPtr = transport.getRcfSession();
            if ( rcfSessionWeakPtr == RcfSessionWeakPtr() )
            {
                // HTTP/HTTPS connections do not hold on to the RcfSession and can't receive pings.
                continue;
            }
            RcfSessionPtr rcfSessionPtr = rcfSessionWeakPtr.lock();
            if (!rcfSessionPtr)
            {
                RCF_LOG_2() << "Dropping subscription. Subscriber has closed connection.";
                iter->reset();
                needToRemove = true;
            }
            else
            {
                boost::uint32_t pingIntervalMs = rcfSessionPtr->getPingIntervalMs();
                if (pingIntervalMs)
                {
                    RCF::Timer pingTimer( rcfSessionPtr->getPingTimestamp() );
                    if (pingTimer.elapsed(5000 + 2*pingIntervalMs))
                    {
                        std::string subscriberUrl = rcfSessionPtr->getClientAddress().string();
                        
                        RCF_LOG_2()(subscriberUrl)(pingIntervalMs) 
                            << "Dropping subscription. Subscriber has not sent pings within the expected ping interval.";

                        iter->reset();
                        needToRemove = true;
                    }
                }
            }
        }

        if (needToRemove)
        {
            eraseRemove(mClientTransports, ClientTransportAutoPtrPtr());
        }
    }