Beispiel #1
0
void
CTCPSocket::shutdownOutput()
{
	bool useNewJob = false;
	{
		CLock lock(&m_mutex);

		// shutdown socket for writing
		try {
			ARCH->closeSocketForWrite(m_socket);
		}
		catch (XArchNetwork&) {
			// ignore
		}

		// shutdown buffer for writing
		if (m_writable) {
			sendEvent(getOutputShutdownEvent());
			onOutputShutdown();
			useNewJob = true;
		}
	}
	if (useNewJob) {
		setJob(newJob());
	}
}
Beispiel #2
0
void
CTCPSocket::onDisconnected()
{
	// disconnected
	onInputShutdown();
	onOutputShutdown();
	m_connected = false;
}
Beispiel #3
0
ISocketMultiplexerJob*
CTCPSocket::serviceConnected(ISocketMultiplexerJob* job,
				bool read, bool write, bool error)
{
	CLock lock(&m_mutex);

	if (error) {
		sendEvent(getDisconnectedEvent());
		onDisconnected();
		return newJob();
	}

	bool needNewJob = false;

	if (write) {
		try {
			// write data
			UInt32 n = m_outputBuffer.getSize();
			const void* buffer = m_outputBuffer.peek(n);
			n = (UInt32)ARCH->writeSocket(m_socket, buffer, n);

			// discard written data
			if (n > 0) {
				m_outputBuffer.pop(n);
				if (m_outputBuffer.getSize() == 0) {
					sendEvent(getOutputFlushedEvent());
					m_flushed = true;
					m_flushed.broadcast();
					needNewJob = true;
				}
			}
		}
		catch (XArchNetworkShutdown&) {
			// remote read end of stream hungup.  our output side
			// has therefore shutdown.
			onOutputShutdown();
			sendEvent(getOutputShutdownEvent());
			if (!m_readable && m_inputBuffer.getSize() == 0) {
				sendEvent(getDisconnectedEvent());
				m_connected = false;
			}
			needNewJob = true;
		}
		catch (XArchNetworkDisconnected&) {
			// stream hungup
			onDisconnected();
			sendEvent(getDisconnectedEvent());
			needNewJob = true;
		}
		catch (XArchNetwork& e) {
			// other write error
			LOG((CLOG_WARN "error writing socket: %s", e.what().c_str()));
			onDisconnected();
			sendEvent(getOutputErrorEvent());
			sendEvent(getDisconnectedEvent());
			needNewJob = true;
		}
	}

	if (read && m_readable) {
		try {
			UInt8 buffer[4096];
			size_t n = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
			if (n > 0) {
				bool wasEmpty = (m_inputBuffer.getSize() == 0);

				// slurp up as much as possible
				do {
					m_inputBuffer.write(buffer, n);
					n = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
				} while (n > 0);

				// send input ready if input buffer was empty
				if (wasEmpty) {
					sendEvent(getInputReadyEvent());
				}
			}
			else {
				// remote write end of stream hungup.  our input side
				// has therefore shutdown but don't flush our buffer
				// since there's still data to be read.
				sendEvent(getInputShutdownEvent());
				if (!m_writable && m_inputBuffer.getSize() == 0) {
					sendEvent(getDisconnectedEvent());
					m_connected = false;
				}
				m_readable = false;
				needNewJob = true;
			}
		}
		catch (XArchNetworkDisconnected&) {
			// stream hungup
			sendEvent(getDisconnectedEvent());
			onDisconnected();
			needNewJob = true;
		}
		catch (XArchNetwork& e) {
			// ignore other read error
			LOG((CLOG_WARN "error reading socket: %s", e.what().c_str()));
		}
	}

	return needNewJob ? newJob() : job;
}
Beispiel #4
0
ISocketMultiplexerJob*
TCPSocket::serviceConnected(ISocketMultiplexerJob* job,
                bool read, bool write, bool error)
{
    Lock lock(&m_mutex);

    if (error) {
        sendEvent(m_events->forISocket().disconnected());
        onDisconnected();
        return newJob();
    }

    EJobResult result = kRetry;
    if (write) {
        try {
            result = doWrite();
        }
        catch (XArchNetworkShutdown&) {
            // remote read end of stream hungup.  our output side
            // has therefore shutdown.
            onOutputShutdown();
            sendEvent(m_events->forIStream().outputShutdown());
            if (!m_readable && m_inputBuffer.getSize() == 0) {
                sendEvent(m_events->forISocket().disconnected());
                m_connected = false;
            }
            result = kNew;
        }
        catch (XArchNetworkDisconnected&) {
            // stream hungup
            onDisconnected();
            sendEvent(m_events->forISocket().disconnected());
            result = kNew;
        }
        catch (XArchNetwork& e) {
            // other write error
            LOG((CLOG_WARN "error writing socket: %s", e.what()));
            onDisconnected();
            sendEvent(m_events->forIStream().outputError());
            sendEvent(m_events->forISocket().disconnected());
            result = kNew;
        }
    }

    if (read && m_readable) {
        try {
            result = doRead();
        }
        catch (XArchNetworkDisconnected&) {
            // stream hungup
            sendEvent(m_events->forISocket().disconnected());
            onDisconnected();
            result = kNew;
        }
        catch (XArchNetwork& e) {
            // ignore other read error
            LOG((CLOG_WARN "error reading socket: %s", e.what()));
        }
    }

    return result == kBreak ? nullptr : result == kNew ? newJob() : job;
}