Beispiel #1
0
void ConnectionDescriptor::Read()
{
	/* Read and dispatch data on a socket that has selected readable.
	 * It's theoretically possible to get and dispatch incoming data on
	 * a socket that has already been scheduled for closing or close-after-writing.
	 * In those cases, we'll leave it up the to protocol handler to "do the
	 * right thing" (which probably means to ignore the incoming data).
	 *
	 * 22Aug06: Chris Ochs reports that on FreeBSD, it's possible to come
	 * here with the socket already closed, after the process receives
	 * a ctrl-C signal (not sure if that's TERM or INT on BSD). The application
	 * was one in which network connections were doing a lot of interleaved reads
	 * and writes.
	 * Since we always write before reading (in order to keep the outbound queues
	 * as light as possible), I think what happened is that an interrupt caused
	 * the socket to be closed in ConnectionDescriptor::Write. We'll then
	 * come here in the same pass through the main event loop, and won't get
	 * cleaned up until immediately after.
	 * We originally asserted that the socket was valid when we got here.
	 * To deal properly with the possibility that we are closed when we get here,
	 * I removed the assert. HOWEVER, the potential for an infinite loop scares me,
	 * so even though this is really clunky, I added a flag to assert that we never
	 * come here more than once after being closed. (FCianfrocca)
	 */

	int sd = GetSocket();
	//assert (sd != INVALID_SOCKET); (original, removed 22Aug06)
	if (sd == INVALID_SOCKET) {
		assert (!bReadAttemptedAfterClose);
		bReadAttemptedAfterClose = true;
		return;
	}

	if (bNotifyReadable) {
		if (EventCallback)
			(*EventCallback)(GetBinding().c_str(), EM_CONNECTION_NOTIFY_READABLE, NULL, 0);
		return;
	}

	LastIo = gCurrentLoopTime;

	int total_bytes_read = 0;
	char readbuffer [16 * 1024 + 1];

	for (int i=0; i < 10; i++) {
		// Don't read just one buffer and then move on. This is faster
		// if there is a lot of incoming.
		// But don't read indefinitely. Give other sockets a chance to run.
		// NOTICE, we're reading one less than the buffer size.
		// That's so we can put a guard byte at the end of what we send
		// to user code.
		

		int r = recv (sd, readbuffer, sizeof(readbuffer) - 1, 0);
		//cerr << "<R:" << r << ">";

		if (r > 0) {
			total_bytes_read += r;
			LastRead = gCurrentLoopTime;

			// Add a null-terminator at the the end of the buffer
			// that we will send to the callback.
			// DO NOT EVER CHANGE THIS. We want to explicitly allow users
			// to be able to depend on this behavior, so they will have
			// the option to do some things faster. Additionally it's
			// a security guard against buffer overflows.
			readbuffer [r] = 0;
			_DispatchInboundData (readbuffer, r);
		}
		else if (r == 0) {
			break;
		}
		else {
			// Basically a would-block, meaning we've read everything there is to read.
			break;
		}

	}


	if (total_bytes_read == 0) {
		// If we read no data on a socket that selected readable,
		// it generally means the other end closed the connection gracefully.
		ScheduleClose (false);
		//bCloseNow = true;
	}

}
Beispiel #2
0
void ConnectionDescriptor::Write()
{
	/* A socket which is in a pending-connect state will select
	 * writable when the disposition of the connect is known.
	 * At that point, check to be sure there are no errors,
	 * and if none, then promote the socket out of the pending
	 * state.
	 * TODO: I haven't figured out how Windows signals errors on
	 * unconnected sockets. Maybe it does the untraditional but
	 * logical thing and makes the socket selectable for error.
	 * If so, it's unsupported here for the time being, and connect
	 * errors will have to be caught by the timeout mechanism.
	 */

	if (bConnectPending) {
		int error;
		socklen_t len;
		len = sizeof(error);
		#ifdef OS_UNIX
		int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, &error, &len);
		#endif
		#ifdef OS_WIN32
		int o = getsockopt (GetSocket(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
		#endif
		if ((o == 0) && (error == 0)) {
			if (EventCallback)
				(*EventCallback)(GetBinding(), EM_CONNECTION_COMPLETED, "", 0);

			// 5May09: Moved epoll/kqueue read/write arming into SetConnectPending, so it can be called
			// from EventMachine_t::AttachFD as well.
			SetConnectPending (false);
		}
		else
			ScheduleClose (false);
			//bCloseNow = true;
	}
	else {

		if (bNotifyWritable) {
			if (EventCallback)
				(*EventCallback)(GetBinding(), EM_CONNECTION_NOTIFY_WRITABLE, NULL, 0);

			_UpdateEvents(false, true);
			return;
		}

		assert(!bWatchOnly);

		/* 5May09: Kqueue bugs on OSX cause one extra writable event to fire even though we're using
		   EV_ONESHOT. We ignore this extra event once, but only the first time. If it happens again,
		   we should fall through to the assert(nbytes>0) failure to catch any EM bugs which might cause
		   ::Write to be called in a busy-loop.
		*/
		#ifdef HAVE_KQUEUE
		if (MyEventMachine->UsingKqueue()) {
			if (OutboundDataSize == 0 && !bGotExtraKqueueEvent) {
				bGotExtraKqueueEvent = true;
				return;
			} else if (OutboundDataSize > 0) {
				bGotExtraKqueueEvent = false;
			}
		}
		#endif

		_WriteOutboundData();
	}
}
Beispiel #3
0
void DatagramDescriptor::Read()
{
	int sd = GetSocket();
	assert (sd != INVALID_SOCKET);
	LastIo = gCurrentLoopTime;

	// This is an extremely large read buffer.
	// In many cases you wouldn't expect to get any more than 4K.
	char readbuffer [16 * 1024];

	for (int i=0; i < 10; i++) {
		// Don't read just one buffer and then move on. This is faster
		// if there is a lot of incoming.
		// But don't read indefinitely. Give other sockets a chance to run.
		// NOTICE, we're reading one less than the buffer size.
		// That's so we can put a guard byte at the end of what we send
		// to user code.

		struct sockaddr_in sin;
		socklen_t slen = sizeof (sin);
		memset (&sin, 0, slen);

		int r = recvfrom (sd, readbuffer, sizeof(readbuffer) - 1, 0, (struct sockaddr*)&sin, &slen);
		//cerr << "<R:" << r << ">";

		// In UDP, a zero-length packet is perfectly legal.
		if (r >= 0) {
			LastRead = gCurrentLoopTime;

			// Add a null-terminator at the the end of the buffer
			// that we will send to the callback.
			// DO NOT EVER CHANGE THIS. We want to explicitly allow users
			// to be able to depend on this behavior, so they will have
			// the option to do some things faster. Additionally it's
			// a security guard against buffer overflows.
			readbuffer [r] = 0;


			// Set up a "temporary" return address so that callers can "reply" to us
			// from within the callback we are about to invoke. That means that ordinary
			// calls to "send_data_to_connection" (which is of course misnamed in this
			// case) will result in packets being sent back to the same place that sent
			// us this one.
			// There is a different call (evma_send_datagram) for cases where the caller
			// actually wants to send a packet somewhere else.

			memset (&ReturnAddress, 0, sizeof(ReturnAddress));
			memcpy (&ReturnAddress, &sin, slen);

			if (EventCallback)
				(*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r);

		}
		else {
			// Basically a would-block, meaning we've read everything there is to read.
			break;
		}

	}


}
Beispiel #4
0
void AcceptorDescriptor::Read()
{
	/* Accept up to a certain number of sockets on the listening connection.
	 * Don't try to accept all that are present, because this would allow a DoS attack
	 * in which no data were ever read or written. We should accept more than one,
	 * if available, to keep the partially accepted sockets from backing up in the kernel.
	 */

	/* Make sure we use non-blocking i/o on the acceptor socket, since we're selecting it
	 * for readability. According to Stevens UNP, it's possible for an acceptor to select readable
	 * and then block when we call accept. For example, the other end resets the connection after
	 * the socket selects readable and before we call accept. The kernel will remove the dead
	 * socket from the accept queue. If the accept queue is now empty, accept will block.
	 */


	struct sockaddr_in pin;
	socklen_t addrlen = sizeof (pin);

	for (int i=0; i < 10; i++) {
		int sd = accept (GetSocket(), (struct sockaddr*)&pin, &addrlen);
		if (sd == INVALID_SOCKET) {
			// This breaks the loop when we've accepted everything on the kernel queue,
			// up to 10 new connections. But what if the *first* accept fails?
			// Does that mean anything serious is happening, beyond the situation
			// described in the note above?
			break;
		}

		// Set the newly-accepted socket non-blocking.
		// On Windows, this may fail because, weirdly, Windows inherits the non-blocking
		// attribute that we applied to the acceptor socket into the accepted one.
		if (!SetSocketNonblocking (sd)) {
		//int val = fcntl (sd, F_GETFL, 0);
		//if (fcntl (sd, F_SETFL, val | O_NONBLOCK) == -1) {
			shutdown (sd, 1);
			closesocket (sd);
			continue;
		}


		// Disable slow-start (Nagle algorithm). Eventually make this configurable.
		int one = 1;
		setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one));


		ConnectionDescriptor *cd = new ConnectionDescriptor (sd, MyEventMachine);
		if (!cd)
			throw std::runtime_error ("no newly accepted connection");
		cd->SetServerMode();
		if (EventCallback) {
			(*EventCallback) (GetBinding(), EM_CONNECTION_ACCEPTED, NULL, cd->GetBinding());
		}
		#ifdef HAVE_EPOLL
		cd->GetEpollEvent()->events = EPOLLIN | (cd->SelectForWrite() ? EPOLLOUT : 0);
		#endif
		assert (MyEventMachine);
		MyEventMachine->Add (cd);
		#ifdef HAVE_KQUEUE
		if (cd->SelectForWrite())
			MyEventMachine->ArmKqueueWriter (cd);
		MyEventMachine->ArmKqueueReader (cd);
		#endif
	}

}
Beispiel #5
0
void ConnectionDescriptor::StartTls()
{
	#ifdef WITH_SSL
	if (SslBox)
		throw std::runtime_error ("SSL/TLS already running on connection");

	SslBox = new SslBox_t (bIsServer, PrivateKeyFilename, CertChainFilename, bSslVerifyPeer, GetBinding());
	_DispatchCiphertext();
	#endif

	#ifdef WITHOUT_SSL
	throw std::runtime_error ("Encryption not available on this event-machine");
	#endif
}
void InputManager::HandleControl( Controller& controller )
{
	//TODO: make this so it's not just cut-and-pasted code iterating over two enums

	if (controller.GetControllerID() == 0)
	{
		int numXboxButtons = sizeof( sBindRecordsOne ) / sizeof(sBindRecordsOne[0] );
		for( int i = 0; i < numXboxButtons; i++ )
		{
			XboxButtonBindRecord& rec = sBindRecordsOne[i];
			
			//Is button currently down
			bool bIsDown = (controller.*rec.CheckFunc)();
			bool bWasDown = _xBoxButtonStates[controller.GetControllerID()][rec.HashKey];
			
			//Update key value
			_xBoxButtonStates[controller.GetControllerID()][rec.HashKey] = bIsDown;
			
			InputBinding* pBinding = GetBinding( rec.HashKey );
			if( pBinding == NULL )
				continue;
			
			if( !bWasDown && bIsDown )
			{
				//BUTTON DOWN
				pBinding->OnKeyDown();
			}
			else if( bWasDown && !bIsDown )
			{
				//BUTTON UP
				pBinding->OnKeyUp();
			}
		}
	}
	else if (controller.GetControllerID() == 1)
	{
		int numXboxButtons = sizeof( sBindRecordsTwo ) / sizeof(sBindRecordsTwo[0] );
		for( int i = 0; i < numXboxButtons; i++ )
		{
			XboxButtonBindRecord& rec = sBindRecordsTwo[i];
			
			//Is button currently down
			bool bIsDown = (controller.*rec.CheckFunc)();
			bool bWasDown = _xBoxButtonStates[controller.GetControllerID()][rec.HashKey];
			
			//Update key value
			_xBoxButtonStates[controller.GetControllerID()][rec.HashKey] = bIsDown;
			
			InputBinding* pBinding = GetBinding( rec.HashKey );
			if( pBinding == NULL )
				continue;
			
			if( !bWasDown && bIsDown )
			{
				//BUTTON DOWN
				pBinding->OnKeyDown();
			}
			else if( bWasDown && !bIsDown )
			{
				//BUTTON UP
				pBinding->OnKeyUp();
			}
		}
	}
	else
	{
		sysLog.Log("Bad controller ID.");
		return;
	}

}
    HRESULT PendingBreakpoint::BindToModule( Module* mod, Program* prog )
    {
        GuardedArea             guard( mBoundBPGuard );

        if ( mDeleted )
            return E_BP_DELETED;
        if ( (mState.flags & PBPSF_VIRTUALIZED) == 0 )
            return E_FAIL;

        HRESULT                 hr = S_OK;
        BpRequestInfo           reqInfo;
        auto_ptr<BPBinder>      binder;

        hr = MakeBinder( mBPRequest, binder );
        if ( FAILED( hr ) )
            return hr;

        // generate bound and error breakpoints
        BPBinderCallback        callback( binder.get(), this, mDocContext.Get(), mDebugger );
        callback.BindToModule( mod, prog );

        if ( mDocContext.Get() == NULL )
        {
            // set up our document context, since we didn't have one
            callback.GetDocumentContext( mDocContext );
        }

        ModuleBinding*  binding = GetBinding( mod->GetId() );
        if ( binding == NULL )
            return E_FAIL;

        // enable all bound BPs if we're enabled
        if ( mState.state == PBPS_ENABLED )
        {
            ModuleBinding&  bind = *binding;

            for ( ModuleBinding::BPList::iterator itBind = bind.BoundBPs.begin();
                itBind != bind.BoundBPs.end();
                itBind++ )
            {
                (*itBind)->Enable( TRUE );
            }
        }

        if ( callback.GetBoundBPCount() > 0 )
        {
            // send a bound event

            CComPtr<IEnumDebugBoundBreakpoints2>    enumBPs;

            hr = EnumBoundBreakpoints( binding, &enumBPs );
            if ( FAILED( hr ) )
                return hr;

            hr = SendBoundEvent( enumBPs );
        }
        else if ( callback.GetErrorBPCount() > 0 )
        {
            // At the beginning, Bind was called, which bound to all mods at the
            // time. If it sent out a bound BP event, then there can be no error.
            // If it sent out an error BP event, then there's no need to repeat it.
            // If you do send out this unneeded event here, then it slows down mod
            // loading a lot. For ex., with 160 mods, mod loading takes ~10x longer.

            // So, don't send an error event!
            hr = S_OK;
        }
        else
            hr = E_FAIL;

        return hr;
    }
Beispiel #8
0
void PipeDescriptor::Read()
{
	int sd = GetSocket();
	if (sd == INVALID_SOCKET) {
		assert (!bReadAttemptedAfterClose);
		bReadAttemptedAfterClose = true;
		return;
	}

	LastIo = gCurrentLoopTime;

	int total_bytes_read = 0;
	char readbuffer [16 * 1024];

	for (int i=0; i < 10; i++) {
		// Don't read just one buffer and then move on. This is faster
		// if there is a lot of incoming.
		// But don't read indefinitely. Give other sockets a chance to run.
		// NOTICE, we're reading one less than the buffer size.
		// That's so we can put a guard byte at the end of what we send
		// to user code.
		// Use read instead of recv, which on Linux gives a "socket operation
		// on nonsocket" error.
		

		int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
		//cerr << "<R:" << r << ">";

		if (r > 0) {
			total_bytes_read += r;
			LastRead = gCurrentLoopTime;

			// Add a null-terminator at the the end of the buffer
			// that we will send to the callback.
			// DO NOT EVER CHANGE THIS. We want to explicitly allow users
			// to be able to depend on this behavior, so they will have
			// the option to do some things faster. Additionally it's
			// a security guard against buffer overflows.
			readbuffer [r] = 0;
			if (EventCallback)
				(*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, readbuffer, r);
			}
		else if (r == 0) {
			break;
		}
		else {
			// Basically a would-block, meaning we've read everything there is to read.
			break;
		}

	}


	if (total_bytes_read == 0) {
		// If we read no data on a socket that selected readable,
		// it generally means the other end closed the connection gracefully.
		ScheduleClose (false);
		//bCloseNow = true;
	}

}