/*!
 * @brief Closes the server socket and brings down the client connections.
 * @param channel Pointer to the TCP channel to close.
 * @param request The request packet.
 * @param context The channel context.
 * @returns Indication of success or failure.
 * @retval ERROR_SUCCESS This value is always returned.
 */
DWORD tcp_channel_server_close(Channel * channel, Packet * request, LPVOID context)
{
    TcpServerContext * ctx = (TcpServerContext *)context;

    do
    {
        dprintf("[TCP-SERVER] tcp_channel_server_close. channel=0x%08X, ctx=0x%08X", channel, ctx);

        if (!ctx)
        {
            break;
        }

        // Set the context channel to NULL so we don't try to close the
        // channel (since it's already being closed)
        ctx->channel = NULL;

        // Free the context
        free_tcp_server_context(ctx);

        // Set the native channel operations context to NULL
        channel_set_native_io_context(channel, NULL);

    } while (0);

    return ERROR_SUCCESS;
}
Beispiel #2
0
/*
 * Bring down a UDP channel an free up the context.
 */
DWORD udp_channel_close( Channel * channel, Packet * request, LPVOID context )
{
	UdpClientContext * ctx = (UdpClientContext *)context;

	do
	{
		dprintf( "[UDP] udp_channel_close. channel=0x%08X, ctx=0x%08X", channel, ctx );

		if( !ctx )
			break;
	
		// Set the context channel to NULL so we don't try to close the
		// channel (since it's already being closed)
		ctx->sock.channel = NULL;

		// Free the context
		free_udp_context( ctx );

		// Set the native channel operations context to NULL
		channel_set_native_io_context( channel, NULL );

	} while( 0 );

	return ERROR_SUCCESS;
}
Beispiel #3
0
/*
 * Closes the established connection and cleans up stale state
 */
static DWORD tcp_channel_client_close(Channel *channel, Packet *request, 
		LPVOID context)
{
	TcpClientContext *ctx = (TcpClientContext *)context;

	if (ctx)
	{
		// Set the context channel to NULL so we don't try to close the
		// channel (since it's already being closed)
		ctx->channel = NULL;

		// Free the context
		free_tcp_client_context(ctx);

		// Set the native channel operations context to NULL
		channel_set_native_io_context(channel, NULL);
	}

	return ERROR_SUCCESS;
}
Beispiel #4
0
/*
 * Callback for when there is data available on the local side of the TCP client connection
 */
DWORD tcp_channel_client_local_notify( Remote * remote, TcpClientContext * ctx )
{
	struct timeval tv  = {0};
	fd_set set         = {0};
	UCHAR  buf[16384]  = {0};
	LONG   dwBytesRead = 0;

	// We select in a loop with a zero second timeout because it's possible
	// that we could get a recv notification and a close notification at once,
	// so we need some way to make sure that we see them both, otherwise the
	// event handle wont get re set to notify us.
	do
	{
		// Reset the notification event
		ResetEvent( ctx->notify );

		FD_ZERO( &set );
		FD_SET( ctx->fd, &set );
		
		tv.tv_sec  = 0;
		tv.tv_usec = 0;

		// Read data from the client connection
		dwBytesRead = recv( ctx->fd, buf, sizeof(buf), 0 );
		
		if( dwBytesRead == SOCKET_ERROR )
		{
			DWORD dwError = WSAGetLastError();
			
			// WSAECONNRESET: The connection was forcibly closed by the remote host.
			// WSAECONNABORTED: The connection was terminated due to a time-out or other failure.
			if( dwError == WSAECONNRESET || dwError == WSAECONNABORTED )
			{
				dprintf( "[TCP] tcp_channel_client_local_notify. [error] closing down channel gracefully. WSAGetLastError=%d", dwError );
				// By setting bytesRead to zero, we can ensure we close down the channel gracefully...
				dwBytesRead = 0;
			}
			else if( dwError == WSAEWOULDBLOCK )
			{
				dprintf( "[TCP] tcp_channel_client_local_notify. channel=0x%08X. recv generated a WSAEWOULDBLOCK", ctx->channel );
				// break and let the scheduler notify us again if needed.
				break;
			}
			else
			{
				dprintf( "[TCP] tcp_channel_client_local_notify. [error] channel=0x%08X read=0x%.8x (ignored). WSAGetLastError=%d", ctx->channel, dwBytesRead, dwError );
				// we loop again because bytesRead is -1.
			}
		}

		if( dwBytesRead == 0 )
		{
			dprintf( "[TCP] tcp_channel_client_local_notify. [closed] channel=0x%08X read=0x%.8x", ctx->channel, dwBytesRead );

			// Set the native channel operations context to NULL
			channel_set_native_io_context( ctx->channel, NULL );
			
			// Sleep for a quarter second
			Sleep( 250 );

			// Free the context
			free_tcp_client_context( ctx );

			// Stop processing
			break;
		}
		else if( dwBytesRead > 0 )
		{
			if( ctx->channel )
			{
				dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=0x%08X read=%d", ctx->channel, dwBytesRead );
				channel_write( ctx->channel, ctx->remote, NULL, 0, buf, dwBytesRead, 0 );
			}
			else
			{
				dprintf( "[TCP] tcp_channel_client_local_notify. [data] channel=<invalid> read=0x%.8x", dwBytesRead );
			}
		}

	} while( select( 1, &set, NULL, NULL, &tv ) > 0 );
	
	return ERROR_SUCCESS;
}
Beispiel #5
0
/*
 * The notify routine for all FD_READ events on the UDP socket.
 */
DWORD udp_channel_notify( Remote * remote, UdpClientContext * ctx )
{
	DWORD dwResult     = ERROR_SUCCESS;
	SOCKADDR_IN from   = {0};
	DWORD dwFromLength = 0;
	DWORD dwBytesRead  = 0;
	BYTE bBuffer[65535];

	do
	{
		ResetEvent( ctx->sock.notify );

		dwFromLength = sizeof( SOCKADDR_IN );

		dwBytesRead = recvfrom( ctx->sock.fd, bBuffer, 65535, 0, (SOCKADDR *)&from, &dwFromLength );
		if( dwBytesRead == SOCKET_ERROR )
		{
			DWORD dwError = WSAGetLastError();

			if( dwError == WSAECONNRESET )
			{
				dprintf( "[UDP] udp_channel_notify. WSAECONNRESET for channel=0x%08X, WSAGetLastError=%d", ctx->sock.channel, dwError );
				// sf: here we have a valid host which sent back an ICMP Port Unreachable message for a previous sendto()
				// we should not close the socket (ctx->sock.fd)
			}
			else
			{
				dprintf( "[UDP] udp_channel_notify. Error on recvfrom with channel=0x%08X, WSAGetLastError=%d", ctx->sock.channel, dwError );
			}

			break;
		}

		if( dwBytesRead == 0 )
		{
			dprintf( "[UDP] udp_channel_notify. channel=0x%08X is being gracefully closed...", ctx->sock.channel );

			channel_set_native_io_context( ctx->sock.channel, NULL );
			
			Sleep( 250 );

			free_udp_context( ctx );

			break;
		}
		else if( dwBytesRead > 0 )
		{
			char * cpPeerHost = NULL;
			Tlv addend[2]     = {0};
			DWORD dwPeerPort  = 0;

			if( !ctx->sock.channel )
				break;

			cpPeerHost = inet_ntoa( from.sin_addr );
			if( !cpPeerHost )
				cpPeerHost = "0.0.0.0";

			dwPeerPort = htonl( ntohs( from.sin_port ) );

			addend[0].header.type   = TLV_TYPE_PEER_HOST;
			addend[0].header.length = (DWORD)(strlen(cpPeerHost) + 1);
			addend[0].buffer        = cpPeerHost;
				
			addend[1].header.type   = TLV_TYPE_PEER_PORT;
			addend[1].header.length = sizeof(DWORD);
			addend[1].buffer        = (PUCHAR)&dwPeerPort;

			dprintf( "[UDP] udp_channel_notify. Data on channel=0x%08X, read %d bytes from %s:%d", ctx->sock.channel, dwBytesRead, cpPeerHost, ntohs( from.sin_port ) );

			channel_write( ctx->sock.channel, ctx->sock.remote, addend, 2, bBuffer, dwBytesRead, NULL );
		}

	} while( 0 );

	return ERROR_SUCCESS;
}