Пример #1
0
/*
 * Shuts the socket down for either reading or writing based on the how
 * parameter supplied by the remote side
 */
DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	SocketContext *ctx = NULL;
	Channel *channel = NULL;
	DWORD result = ERROR_SUCCESS;
	DWORD how;

	// Find the associated channel
	channel = channel_find_by_id(packet_get_tlv_value_uint(packet, 
				TLV_TYPE_CHANNEL_ID));
	how = packet_get_tlv_value_uint(packet, TLV_TYPE_SHUTDOWN_HOW);

	// If the channel and channel context are valid...
	if ((channel) &&
	    ((ctx = channel_get_native_io_context(channel))))
	{
		if (shutdown(ctx->fd, how) == SOCKET_ERROR)
			result = WSAGetLastError();
	}

	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}
/*
 * core_channel_tell
 * -----------------
 *
 * req: TLV_TYPE_CHANNEL_ID  -- The channel identifier to check tell on
 */
DWORD remote_request_core_channel_tell(Remote *remote, Packet *packet)
{
	Channel *channel = NULL;
	Packet *response = packet_create_response(packet);
	DWORD result = ERROR_SUCCESS;
	LONG offset = 0;

	do
	{
		// Lookup the channel by its identifier
		if (!(channel = channel_find_by_id(
				packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID))))
		{
			result = ERROR_NOT_FOUND;
			break;
		}

		lock_acquire( channel->lock );

		// Make sure this class is compatible
		if (channel_get_class(channel) != CHANNEL_CLASS_POOL)
		{
			result = ERROR_NOT_SUPPORTED;
			break;
		}

		// Call the function if it's set
		if (channel->ops.pool.tell)
			result = channel->ops.pool.tell(channel, packet, 
					channel->ops.pool.native.context, 
					&offset);
		else
			result = ERROR_NOT_SUPPORTED;

	} while (0);

	if( channel )
		lock_release( channel->lock );

	// Add the offset
	packet_add_tlv_uint(response, TLV_TYPE_SEEK_POS, offset);

	// Transmit the response
	packet_transmit_response(result, remote, response);

	return result;
}
Пример #3
0
/*
 * Shuts the socket down for either reading or writing based on the how
 * parameter supplied by the remote side
 */
DWORD request_net_socket_tcp_shutdown(Remote *remote, Packet *packet)
{
	DWORD dwResult      = ERROR_SUCCESS;
	Packet * response   = NULL;
	SocketContext * ctx = NULL;
	Channel * channel   = NULL;
	DWORD cid           = 0;
	DWORD how           = 0;

	do
	{
		dprintf( "[TCP] entering request_net_socket_tcp_shutdown" );
		response = packet_create_response( packet );
		if( !response )
			BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. response == NULL", ERROR_NOT_ENOUGH_MEMORY );

		cid = packet_get_tlv_value_uint( packet, TLV_TYPE_CHANNEL_ID );
		how = packet_get_tlv_value_uint( packet, TLV_TYPE_SHUTDOWN_HOW );

		channel = channel_find_by_id( cid );
		if( !response )
			BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. channel == NULL", ERROR_INVALID_HANDLE );

		dprintf( "[TCP] request_net_socket_tcp_shutdown. channel=0x%08X, cid=%d", channel, cid );

		ctx = channel_get_native_io_context( channel );
		if( !ctx )
			BREAK_WITH_ERROR( "[TCP] request_net_socket_tcp_shutdown. ctx == NULL", ERROR_INVALID_HANDLE );

		if( shutdown( ctx->fd, how ) == SOCKET_ERROR )
			BREAK_ON_WSAERROR( "[TCP] request_net_socket_tcp_shutdown. shutdown failed" );

		// sf: we dont seem to need to call this here, as the channels tcp_channel_client_local_notify() will 
		// catch the socket closure and call free_socket_context() for us, due the the FD_READ|FD_CLOSE flags 
		// being passed to WSAEventSelect for the notify event in create_tcp_client_channel().
		// This avoids a double call (from two different threads) and subsequent access violation in some edge cases.
		//free_socket_context( ctx );

	} while( 0 );

	packet_transmit_response( dwResult, remote, response );

	dprintf( "[TCP] leaving request_net_socket_tcp_shutdown" );
	
	return ERROR_SUCCESS;
}
/*
 * core_channel_interact
 * ---------------------
 *
 * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to interact with
 * req: TLV_TYPE_BOOL       -- True if interactive, false if not.
 */
DWORD remote_request_core_channel_interact(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	Channel *channel = NULL;
	DWORD channelId;
	DWORD result = ERROR_SUCCESS;
	BOOLEAN interact;

	// Get the channel identifier
	channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);
	interact  = packet_get_tlv_value_bool(packet, TLV_TYPE_BOOL);

	// If the channel is found, set the interactive flag accordingly
	if ((channel = channel_find_by_id(channelId)))
	{
		lock_acquire( channel->lock );

		// If the response packet is valid
		if ((response) &&
		    (channel_get_class(channel) != CHANNEL_CLASS_BUFFERED))
		{
			NativeChannelOps *native = (NativeChannelOps *)&channel->ops;

			// Check to see if this channel has a registered interact handler
			dprintf( "[DISPATCH] attempting to set interactive: %d context 0x%p", interact, native->context );
			if (native->interact) {
				result = native->interact(channel, packet, native->context, interact);
			}
		}

		// Set the channel's interactive state
		channel_set_interactive(channel, interact);

		lock_release( channel->lock );
	}

	// Send the response to the requestor so that the interaction can be 
	// complete
	packet_transmit_response(result, remote, response);

	return ERROR_SUCCESS;
}
/*
 * core_channel_close
 * ------------------
 *
 * Closes a previously opened channel.
 *
 * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close
 */
DWORD remote_request_core_channel_close(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	DWORD res = ERROR_SUCCESS, channelId;
	Channel *channel = NULL;

	dprintf("[CHANNEL] remote_request_core_channel_close.");

	do
	{
		// Get the channel identifier
		channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);

		// Try to locate the specified channel
		if (!(channel = channel_find_by_id(channelId)))
		{
			res = ERROR_NOT_FOUND;
			break;
		}

		// Destroy the channel
		channel_destroy(channel, packet);

		if (response)
		{
			packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId);
		}

	} while (0);

	// Transmit the acknowledgement
	if (response)
	{
		packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);

		res = PACKET_TRANSMIT(remote, response, NULL);
	}

	return res;
}
/*
 * core_channel_close (response)
 * ------------------
 *
 * Removes the local instance of the channel
 *
 * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to close
 */
DWORD remote_response_core_channel_close(Remote *remote, Packet *packet)
{
	DWORD res = ERROR_SUCCESS, channelId;
	Channel *channel = NULL;

	do
	{
		// Get the channel identifier
		channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);

		// Try to locate the specified channel
		if (!(channel = channel_find_by_id(channelId)))
		{
			res = ERROR_NOT_FOUND;
			break;
		}

		// Destroy the channel
		channel_destroy(channel, packet);

	} while (0);

	return res;
}
/*
 * core_channel_read
 * -----------------
 *
 * From from the local buffer and write back to the requester
 *
 * Takes TLVs:
 *
 * req: TLV_TYPE_CHANNEL_ID -- The channel identifier to read from
 * req: TLV_TYPE_LENGTH     -- The number of bytes to read
 */
DWORD remote_request_core_channel_read(Remote *remote, Packet *packet)
{
	DWORD res = ERROR_SUCCESS, bytesToRead, bytesRead, channelId;
	Packet *response = packet_create_response(packet);
	PUCHAR temporaryBuffer = NULL;
	Channel *channel = NULL;

	do
	{
		if (!response)
		{
			res = ERROR_NOT_ENOUGH_MEMORY;
			break;
		}

		// Get the number of bytes to read
		bytesToRead = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH);
		channelId   = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);

		// Try to locate the specified channel
		if (!(channel = channel_find_by_id(channelId)))
		{
			res = ERROR_NOT_FOUND;
			break;
		}

		lock_acquire( channel->lock );

		// Allocate temporary storage
		if (!(temporaryBuffer = (PUCHAR)malloc(bytesToRead)))
		{
			res = ERROR_NOT_ENOUGH_MEMORY;
			break;
		}

		switch (channel_get_class(channel))
		{
			// If it's buffered, read from the local buffer and either transmit 
			// the buffer in the response or write it back asynchronously
			// depending on the mode of the channel.
			case CHANNEL_CLASS_BUFFERED:
				// Read in from local
				res = channel_read_from_buffered(channel, temporaryBuffer, 
				    bytesToRead, (PULONG)&bytesRead);
				break;
			// Handle read I/O for the pool class
			case CHANNEL_CLASS_POOL:
				// If the channel has a read handler
				if (channel->ops.pool.read)
					res = channel->ops.pool.read(channel, packet, 
							channel->ops.pool.native.context, temporaryBuffer, 
							bytesToRead, &bytesRead);
				else
					res = ERROR_NOT_SUPPORTED;
				break;
			default:
				res = ERROR_NOT_SUPPORTED;
		}

		// If we've so far been successful and we have a temporary buffer...
		if ((res == ERROR_SUCCESS) &&(temporaryBuffer) && (bytesRead))
		{
			// If the channel should operate synchronously, add the data to theresponse
			if (channel_is_flag(channel, CHANNEL_FLAG_SYNCHRONOUS))
			{
				// if the channel data is ment to be compressed, compress it!
				if( channel_is_flag( channel, CHANNEL_FLAG_COMPRESS ) )
					packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA|TLV_META_TYPE_COMPRESSED, temporaryBuffer, bytesRead);
				else
					packet_add_tlv_raw(response, TLV_TYPE_CHANNEL_DATA, temporaryBuffer, bytesRead);

				res = ERROR_SUCCESS;
			}
			// Otherwise, asynchronously write the buffer to the remote endpoint
			else
			{
				if ((res = channel_write(channel, remote, NULL, 0, temporaryBuffer, bytesRead, NULL)) != ERROR_SUCCESS)
					break;
			}
		}

	} while (0);
	
	if( channel )
		lock_release( channel->lock );

	if (temporaryBuffer)
		free(temporaryBuffer);

	// Transmit the acknowledgement
	if (response)
	{
		packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
		packet_add_tlv_uint(response, TLV_TYPE_LENGTH, bytesRead);
		packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId);

		res = packet_transmit(remote, response, NULL);
	}

	return res;
}
/*
 * core_channel_write
 * ------------------
 *
 * Write data from a channel into the local output buffer for it
 */
DWORD remote_request_core_channel_write(Remote *remote, Packet *packet)
{
	Packet *response = packet_create_response(packet);
	DWORD res = ERROR_SUCCESS, channelId, written = 0;
	Tlv channelData;
	Channel * channel = NULL;

	do
	{
		channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);

		// Try to locate the specified channel
		if (!(channel = channel_find_by_id(channelId)))
		{
			res = ERROR_NOT_FOUND;
			break;
		}

		lock_acquire( channel->lock );

		// Get the channel data buffer
		if ((res = packet_get_tlv(packet, TLV_TYPE_CHANNEL_DATA, &channelData)) != ERROR_SUCCESS)
			break;

		// Handle the write operation differently based on the class of channel
		switch (channel_get_class(channel))
		{
			// If it's buffered, write it to the local buffer cache
			case CHANNEL_CLASS_BUFFERED:
				res = channel_write_to_buffered(channel, channelData.buffer, channelData.header.length, (PULONG)&written);
				break;
			// If it's non-buffered, call the native write operation handler if
			// one is implemented
			default:
				{
					NativeChannelOps *ops = (NativeChannelOps *)&channel->ops;
					if (ops->write)
						res = ops->write(channel, packet, ops->context, 
								channelData.buffer, channelData.header.length, 
								&written);
					else
						res = ERROR_NOT_SUPPORTED;
				}
				break;
		}

	} while (0);

	if( channel )
		lock_release( channel->lock );

	// Transmit the acknowledgement
	if (response)
	{
		packet_add_tlv_uint(response, TLV_TYPE_RESULT, res);
		packet_add_tlv_uint(response, TLV_TYPE_LENGTH, written);
		packet_add_tlv_uint(response, TLV_TYPE_CHANNEL_ID, channelId);

		res = packet_transmit(remote, response, NULL);
	}

	return res;
}
Пример #9
0
/*
 * Channel completion routine dispatcher
 */
DWORD _channel_packet_completion_routine(Remote *remote, Packet *packet,
        LPVOID context, LPCSTR method, DWORD result)
{
    ChannelCompletionRoutine *comp = (ChannelCompletionRoutine *)context;
    DWORD channelId = packet_get_tlv_value_uint(packet, TLV_TYPE_CHANNEL_ID);
    Channel *channel = channel_find_by_id(channelId);
    DWORD res = ERROR_NOT_FOUND;


    dprintf( "[CHANNEL] _channel_packet_completion_routine. channel=0x%08X method=%s", channel, method );

    // If the channel was not found and it isn't an open request, return failure
    if (!channel && strcmp(method, "core_channel_open"))
        return ERROR_NOT_FOUND;

    if ((!strcmp(method, "core_channel_open")) &&
            (comp->routine.open))
        res = comp->routine.open(remote, channel, comp->context, result);
    else if ((!strcmp(method, "core_channel_read")) &&
             (comp->routine.read))
    {
        ULONG length = 0, realLength = 0;
        PUCHAR buffer = NULL;

        // Get the number of bytes written
        length = packet_get_tlv_value_uint(packet, TLV_TYPE_LENGTH);

        // Allocate storage for it
        if ((length) && (buffer = (PUCHAR)malloc(length)))
        {
            memset(buffer, 0, length);

            channel_read_from_buffered(channel, buffer, length, &realLength);
        }

        res = comp->routine.read(remote, channel, comp->context, result,
                                 buffer, realLength);

        if (buffer)
            free(buffer);
    }
    else if ((!strcmp(method, "core_channel_write")) &&
             (comp->routine.write))
    {
        Tlv lengthTlv;
        ULONG length = 0;

        // Get the number of bytes written to the channel
        if ((packet_get_tlv(packet, TLV_TYPE_LENGTH, &lengthTlv)
                == ERROR_SUCCESS) &&
                (lengthTlv.header.length >= sizeof(DWORD)))
            length = ntohl(*(LPDWORD)lengthTlv.buffer);

        res = comp->routine.write(remote, channel, comp->context, result,
                                  length);
    }
    else if ((!strcmp(method, "core_channel_close")) &&
             (comp->routine.close))
        res = comp->routine.close(remote, channel, comp->context, result);
    else if ((!strcmp(method, "core_channel_interact")) &&
             (comp->routine.interact))
        res = comp->routine.interact(remote, channel, comp->context, result);

    // Deallocate the completion context
    free(comp);

    return res;
}