예제 #1
0
bool PipeDescriptor::SelectForWrite()
{
	/* Pipe descriptors, being local by definition, don't have
	 * a pending state, so this is simpler than for the
	 * ConnectionDescriptor object.
	 */
	return (GetOutboundDataSize() > 0);
}
예제 #2
0
파일: ed.cpp 프로젝트: alltom/easyget
bool EventableDescriptor::ShouldDelete()
{
	/* For use by a socket manager, which needs to know if this object
	 * should be removed from scheduling events and deleted.
	 * Has an immediate close been scheduled, or are we already closed?
	 * If either of these are the case, return true. In theory, the manager will
	 * then delete us, which in turn will make sure the socket is closed.
	 * Note, if bCloseAfterWriting is true, we check a virtual method to see
	 * if there is outbound data to write, and only request a close if there is none.
	 */

	return ((MySocket == INVALID_SOCKET) || bCloseNow || (bCloseAfterWriting && (GetOutboundDataSize() <= 0)));
}
예제 #3
0
파일: ed.cpp 프로젝트: alltom/easyget
bool ConnectionDescriptor::SelectForWrite()
{
  /* Cf the notes under SelectForRead.
   * In a pending-connect state, we ALWAYS select for writable.
   * In a normal state, we only select for writable when we
   * have outgoing data to send.
   */

  if (bConnectPending || bNotifyWritable)
    return true;
  else {
    return (GetOutboundDataSize() > 0);
  }
}
예제 #4
0
int ConnectionDescriptor::SendOutboundData (const char *data, int length)
{
	if (bWatchOnly)
		throw std::runtime_error ("cannot send data on a 'watch only' connection");

	if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)(GetOutboundDataSize() + length) > MaxOutboundBufSize)
		ProxiedFrom->Pause();

	#ifdef WITH_SSL
	if (SslBox) {
		if (length > 0) {
			int w = SslBox->PutPlaintext (data, length);
			if (w < 0)
				ScheduleClose (false);
			else
				_DispatchCiphertext();
		}
		// TODO: What's the correct return value?
		return 1; // That's a wild guess, almost certainly wrong.
	}
	else
	#endif
		return _SendRawOutboundData (data, length);
}
예제 #5
0
void ConnectionDescriptor::_WriteOutboundData()
{
	/* This is a helper function called by ::Write.
	 * It's possible for a socket to select writable and then no longer
	 * be writable by the time we get around to writing. The kernel might
	 * have used up its available output buffers between the select call
	 * and when we get here. So this condition is not an error.
	 *
	 * 20Jul07, added the same kind of protection against an invalid socket
	 * that is at the top of ::Read. Not entirely how this could happen in 
	 * real life (connection-reset from the remote peer, perhaps?), but I'm
	 * doing it to address some reports of crashing under heavy loads.
	 */

	int sd = GetSocket();
	//assert (sd != INVALID_SOCKET);
	if (sd == INVALID_SOCKET) {
		assert (!bWriteAttemptedAfterClose);
		bWriteAttemptedAfterClose = true;
		return;
	}

	LastActivity = MyEventMachine->GetCurrentLoopTime();
	size_t nbytes = 0;

	#ifdef HAVE_WRITEV
	int iovcnt = OutboundPages.size();
	// Max of 16 outbound pages at a time
	if (iovcnt > 16) iovcnt = 16;

	#ifdef CC_SUNWspro
	struct iovec iov[16];
	#else
	struct iovec iov[ iovcnt ];
	#endif

	for(int i = 0; i < iovcnt; i++){
		OutboundPage *op = &(OutboundPages[i]);
		#ifdef CC_SUNWspro
		iov[i].iov_base = (char *)(op->Buffer + op->Offset);
		#else
		iov[i].iov_base = (void *)(op->Buffer + op->Offset);
		#endif
		iov[i].iov_len	= op->Length - op->Offset;

		nbytes += iov[i].iov_len;
	}
	#else
	char output_buffer [16 * 1024];

	while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
		OutboundPage *op = &(OutboundPages[0]);
		if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
			memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
			nbytes += (op->Length - op->Offset);
			op->Free();
			OutboundPages.pop_front();
		}
		else {
			int len = sizeof(output_buffer) - nbytes;
			memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
			op->Offset += len;
			nbytes += len;
		}
	}
	#endif

	// We should never have gotten here if there were no data to write,
	// so assert that as a sanity check.
	// Don't bother to make sure nbytes is less than output_buffer because
	// if it were we probably would have crashed already.
	assert (nbytes > 0);

	assert (GetSocket() != INVALID_SOCKET);
	#ifdef HAVE_WRITEV
	int bytes_written = writev (GetSocket(), iov, iovcnt);
	#else
	int bytes_written = write (GetSocket(), output_buffer, nbytes);
	#endif

	bool err = false;
	if (bytes_written < 0) {
		err = true;
		bytes_written = 0;
	}

	assert (bytes_written >= 0);
	OutboundDataSize -= bytes_written;

	if (ProxiedFrom && MaxOutboundBufSize && (unsigned int)GetOutboundDataSize() < MaxOutboundBufSize && ProxiedFrom->IsPaused())
		ProxiedFrom->Resume();

	#ifdef HAVE_WRITEV
	if (!err) {
		unsigned int sent = bytes_written;
		deque<OutboundPage>::iterator op = OutboundPages.begin();

		for (int i = 0; i < iovcnt; i++) {
			if (iov[i].iov_len <= sent) {
				// Sent this page in full, free it.
				op->Free();
				OutboundPages.pop_front();

				sent -= iov[i].iov_len;
			} else {
				// Sent part (or none) of this page, increment offset to send the remainder
				op->Offset += sent;
				break;
			}

			// Shouldn't be possible run out of pages before the loop ends
			assert(op != OutboundPages.end());
			*op++;
		}
	}
	#else
	if ((size_t)bytes_written < nbytes) {
		int len = nbytes - bytes_written;
		char *buffer = (char*) malloc (len + 1);
		if (!buffer)
			throw std::runtime_error ("bad alloc throwing back data");
		memcpy (buffer, output_buffer + bytes_written, len);
		buffer [len] = 0;
		OutboundPages.push_front (OutboundPage (buffer, len));
	}
	#endif

	_UpdateEvents(false, true);

	if (err) {
		#ifdef OS_UNIX
		if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK) && (errno != EINTR))
		#endif
		#ifdef OS_WIN32
		if ((errno != WSAEINPROGRESS) && (errno != WSAEWOULDBLOCK))
		#endif
			Close();
	}
}