/*
 * 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;
}
예제 #2
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;
}