int MulticastClientTransport::send( 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; }
int MulticastClientTransport::send( ClientTransportCallback & clientStub, const std::vector<ByteBuffer> & data, unsigned int timeoutMs) { // NB: As the same buffer is sent on all transports, the transports and // filters should never modify the buffer. Any transport that transforms // data needs to do so in a separate per-transport buffer. RCF_UNUSED_VARIABLE(timeoutMs); RCF_LOG_2()(lengthByteBuffers(data))(timeoutMs) << "MulticastClientTransport::send() - entry."; mLastRequestSize = lengthByteBuffers(data); mRunningTotalBytesSent += mLastRequestSize; bringInNewTransports(); Lock lock(mClientTransportsMutex); std::size_t transportsInitial = mClientTransports.size(); PublishCompletionInfo info( mClientTransports.size() ); // Setup completion handlers. std::vector<PublishCompletionHandler> handlers( mClientTransports.size() ); for (std::size_t i=0; i<mClientTransports.size(); ++i) { ClientTransport * pTransport = (*mClientTransports[i]).get(); handlers[i] = PublishCompletionHandler(pTransport, &info); } // Async send on all transports. for (std::size_t i=0; i<handlers.size(); ++i) { try { handlers[i].mpClientTransport->setAsync(true); handlers[i].mpClientTransport->send(handlers[i], data, 0); } catch(const Exception &e) { Exception err( _RcfError_SyncPublishError(e.what()) ); handlers[i].onError(err); } } // Wait for async completions. boost::uint32_t completionDurationMs = 0; { Timer timer; info.wait(timeoutMs); completionDurationMs = timer.getDurationMs(); } // Cancel any outstanding sends. for (std::size_t i=0; i<handlers.size(); ++i) { if (!handlers[i].mCompleted) { (*mClientTransports[i])->cancel(); RCF_LOG_2()(i) << "MulticastClientTransport::send() - cancel send."; } } // Wait for canceled ops to complete. boost::uint32_t cancelDurationMs = 0; { Timer timer; info.wait(timeoutMs); cancelDurationMs = timer.getDurationMs(); } RCF_ASSERT(info.getCompletionCount() == handlers.size()); // Close and remove any subscriber transports with errors. std::size_t transportsRemoved = 0; for (std::size_t i=0; i<handlers.size(); ++i) { RCF_ASSERT(handlers[i].mCompleted); if (!handlers[i].mOk) { mClientTransports[i] = ClientTransportAutoPtrPtr(); ++transportsRemoved; RCF_LOG_2()(i)(handlers[i].mCompleted)(handlers[i].mOk)(handlers[i].mError) << "MulticastClientTransport::send() - remove subscriber transport."; } } eraseRemove(mClientTransports, ClientTransportAutoPtrPtr()); clientStub.onSendCompleted(); std::size_t transportsFinal = transportsInitial - transportsRemoved; RCF_LOG_2() (lengthByteBuffers(data))(completionDurationMs)(cancelDurationMs)(transportsInitial)(transportsFinal) << "MulticastClientTransport::send() - exit."; return 1; }