void AsynchConnector::connComplete(DispatchHandle& h) { int errCode = socket.getError(); if (errCode == 0) { h.stopWatch(); try { socket.finishConnect(sa); } catch (const std::exception& e) { failCallback(socket, 0, e.what()); DispatchHandle::doDelete(); return; } connCallback(socket); } else { // Retry while we cause an immediate exception // (asynch failure will be handled by re-entering here at the top) while (sa.nextAddress()) { try { // Try next address without deleting ourselves QPID_LOG(debug, "Ignored socket connect error: " << strError(errCode)); QPID_LOG(info, "Retrying connect: " << sa.asString()); socket.connect(sa); return; } catch (const std::exception& e) { QPID_LOG(debug, "Ignored socket connect exception: " << e.what()); } errCode = socket.getError(); } h.stopWatch(); failCallback(socket, errCode, strError(errCode)); } DispatchHandle::doDelete(); }
/* * Close the socket and callback to say we've done it */ void AsynchIO::close(DispatchHandle& h) { h.stopWatch(); socket.close(); if (closedCallback) { closedCallback(*this, socket); } }
void SslIO::disconnected(DispatchHandle& h) { // If we've already queued close do it instead of disconnected callback if (queuedClose) { close(h); } else if (disCallback) { disCallback(*this); h.unwatch(); } }
void SslConnector::connComplete(DispatchHandle& h) { int errCode = socket.getError(); h.stopWatch(); if (errCode == 0) { connCallback(socket); DispatchHandle::doDelete(); } else { // TODO: This need to be fixed as strerror isn't thread safe failure(errCode, std::string(::strerror(errCode))); } }
void SslAcceptorTmpl<T>::readable(DispatchHandle& h) { Socket* s; do { errno = 0; // TODO: Currently we ignore the peers address, perhaps we should // log it or use it for connection acceptance. try { s = socket.accept(); if (s) { acceptedCallback(*s); } else { break; } } catch (const std::exception& e) { QPID_LOG(error, "Could not accept socket: " << e.what()); } } while (true); h.rewatch(); }
/* * We carry on writing whilst we have data to write and we can write */ void AsynchIO::writeable(DispatchHandle& h) { AbsTime writeStartTime = AbsTime::now(); size_t total = 0; int writeCalls = 0; do { // See if we've got something to write if (!writeQueue.empty()) { // Write buffer BufferBase* buff = writeQueue.back(); writeQueue.pop_back(); errno = 0; assert(buff->dataStart+buff->dataCount <= buff->byteCount); int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount); int64_t duration = Duration(writeStartTime, AbsTime::now()); ++writeCalls; if (rc >= 0) { threadWriteTotal += rc; total += rc; // If we didn't write full buffer put rest back if (rc != buff->dataCount) { buff->dataStart += rc; buff->dataCount -= rc; writeQueue.push_back(buff); QPID_PROBE4(asynchio_write_finished_done, &h, duration, total, writeCalls); break; } // Recycle the buffer queueReadBuffer(buff); // Stop writing if we've overrun our timeslot if (duration > threadMaxIoTimeNs) { QPID_PROBE4(asynchio_write_finished_maxtime, &h, duration, total, writeCalls); break; } } else { // Put buffer back writeQueue.push_back(buff); QPID_PROBE5(asynchio_write_finished_error, &h, duration, total, writeCalls, errno); if (errno == ECONNRESET || errno == EPIPE) { // Just stop watching for write here - we'll get a // disconnect callback soon enough h.unwatchWrite(); break; } else if (errno == EAGAIN) { // We have just put a buffer back so we know // we can carry on watching for writes break; } else { // Report error then just treat as a socket disconnect QPID_LOG(error, "Error writing socket: " << qpid::sys::strError(errno) << "(" << errno << ")" ); h.unwatchWrite(); break; } } } else { int64_t duration = Duration(writeStartTime, AbsTime::now()); (void) duration; // force duration to be used if no probes are compiled // If we're waiting to close the socket then can do it now as there is nothing to write if (queuedClose) { close(h); QPID_PROBE4(asynchio_write_finished_closed, &h, duration, total, writeCalls); break; } // Fd is writable, but nothing to write if (idleCallback) { writePending = false; idleCallback(*this); } // If we still have no buffers to write we can't do anything more if (writeQueue.empty() && !writePending && !queuedClose) { h.unwatchWrite(); // The following handles the case where writePending is // set to true after the test above; in this case its // possible that the unwatchWrite overwrites the // desired rewatchWrite so we correct that here if (writePending) h.rewatchWrite(); QPID_PROBE4(asynchio_write_finished_nodata, &h, duration, total, writeCalls); break; } } } while (true); ++threadWriteCount; return; }
/* * We keep on reading as long as we have something to read, a buffer * to put it in and reading is not stopped by flow control. */ void AsynchIO::readable(DispatchHandle& h) { AbsTime readStartTime = AbsTime::now(); size_t total = 0; int readCalls = 0; do { // (Try to) get a buffer if (!bufferQueue.empty()) { // Read into buffer BufferBase* buff = bufferQueue.front(); assert(buff); bufferQueue.pop_front(); errno = 0; int readCount = buff->byteCount-buff->dataCount; int rc = socket.read(buff->bytes + buff->dataCount, readCount); int64_t duration = Duration(readStartTime, AbsTime::now()); ++readCalls; if (rc > 0) { buff->dataCount += rc; threadReadTotal += rc; total += rc; readCallback(*this, buff); if (rc != readCount) { // If we didn't fill the read buffer then time to stop reading QPID_PROBE4(asynchio_read_finished_done, &h, duration, total, readCalls); break; } // Stop reading if we've overrun our timeslot if ( duration > threadMaxIoTimeNs) { QPID_PROBE4(asynchio_read_finished_maxtime, &h, duration, total, readCalls); break; } } else { // Put buffer back (at front so it doesn't interfere with unread buffers) bufferQueue.push_front(buff); assert(buff); QPID_PROBE5(asynchio_read_finished_error, &h, duration, total, readCalls, errno); // Eof or other side has gone away if (rc == 0 || errno == ECONNRESET) { eofCallback(*this); h.unwatchRead(); break; } else if (errno == EAGAIN) { // We have just put a buffer back so we know // we can carry on watching for reads break; } else { // Report error then just treat as a socket disconnect QPID_LOG(error, "Error reading socket: " << qpid::sys::strError(errno) << "(" << errno << ")" ); eofCallback(*this); h.unwatchRead(); break; } } } else { // Something to read but no buffer if (emptyCallback) { emptyCallback(*this); } // If we still have no buffers we can't do anything more if (bufferQueue.empty()) { h.unwatchRead(); QPID_PROBE4(asynchio_read_finished_nobuffers, &h, Duration(readStartTime, AbsTime::now()), total, readCalls); break; } } } while (true); ++threadReadCount; return; }
void AsynchAcceptor::start(Poller::shared_ptr poller) { handle.startWatch(poller); }
void reader(DispatchHandle& h, int fd) { readBytes += readALot(fd); h.rewatch(); }
void writer(DispatchHandle& h, int fd, const string& s) { writtenBytes += writeALot(fd, s); h.rewatch(); }
/* * We carry on writing whilst we have data to write and we can write */ void SslIO::writeable(DispatchHandle& h) { AbsTime writeStartTime = AbsTime::now(); do { // See if we've got something to write if (!writeQueue.empty()) { // Write buffer BufferBase* buff = writeQueue.back(); writeQueue.pop_back(); errno = 0; assert(buff->dataStart+buff->dataCount <= buff->byteCount); int rc = socket.write(buff->bytes+buff->dataStart, buff->dataCount); if (rc >= 0) { threadWriteTotal += rc; // If we didn't write full buffer put rest back if (rc != buff->dataCount) { buff->dataStart += rc; buff->dataCount -= rc; writeQueue.push_back(buff); break; } // Recycle the buffer queueReadBuffer(buff); // Stop writing if we've overrun our timeslot if (Duration(writeStartTime, AbsTime::now()) > threadMaxIoTimeNs) { break; } } else { // Put buffer back writeQueue.push_back(buff); if (errno == ECONNRESET || errno == EPIPE) { // Just stop watching for write here - we'll get a // disconnect callback soon enough h.unwatchWrite(); break; } else if (errno == EAGAIN) { // We have just put a buffer back so we know // we can carry on watching for writes break; } else { QPID_LOG(error, "Error writing to socket: " << getErrorString(PR_GetError())); h.unwatchWrite(); break; } } } else { // If we're waiting to close the socket then can do it now as there is nothing to write if (queuedClose) { close(h); break; } // Fd is writable, but nothing to write if (idleCallback) { writePending = false; idleCallback(*this); } // If we still have no buffers to write we can't do anything more if (writeQueue.empty() && !writePending && !queuedClose) { h.unwatchWrite(); // The following handles the case where writePending is // set to true after the test above; in this case its // possible that the unwatchWrite overwrites the // desired rewatchWrite so we correct that here if (writePending) h.rewatchWrite(); break; } } } while (true); ++threadWriteCount; return; }
/* * We keep on reading as long as we have something to read and a buffer to put * it in */ void SslIO::readable(DispatchHandle& h) { AbsTime readStartTime = AbsTime::now(); do { // (Try to) get a buffer if (!bufferQueue.empty()) { // Read into buffer BufferBase* buff = bufferQueue.front(); assert(buff); bufferQueue.pop_front(); errno = 0; int readCount = buff->byteCount-buff->dataCount; int rc = socket.read(buff->bytes + buff->dataCount, readCount); if (rc > 0) { buff->dataCount += rc; threadReadTotal += rc; readCallback(*this, buff); if (rc != readCount) { // If we didn't fill the read buffer then time to stop reading break; } // Stop reading if we've overrun our timeslot if (Duration(readStartTime, AbsTime::now()) > threadMaxIoTimeNs) { break; } } else { // Put buffer back (at front so it doesn't interfere with unread buffers) bufferQueue.push_front(buff); assert(buff); // Eof or other side has gone away if (rc == 0 || errno == ECONNRESET) { eofCallback(*this); h.unwatchRead(); break; } else if (errno == EAGAIN) { // We have just put a buffer back so we know // we can carry on watching for reads break; } else { // Report error then just treat as a socket disconnect QPID_LOG(error, "Error reading socket: " << getErrorString(PR_GetError())); eofCallback(*this); h.unwatchRead(); break; } } } else { // Something to read but no buffer if (emptyCallback) { emptyCallback(*this); } // If we still have no buffers we can't do anything more if (bufferQueue.empty()) { h.unwatchRead(); break; } } } while (true); ++threadReadCount; return; }