void guac_rdpdr_fs_process_set_rename_info(guac_rdpdr_device* device,
        wStream* input_stream, int file_id, int completion_id, int length) {

    int result;
    int filename_length;
    wStream* output_stream;
    char destination_path[GUAC_RDP_FS_MAX_PATH];

    /* Read structure */
    Stream_Seek_UINT8(input_stream); /* ReplaceIfExists */
    Stream_Seek_UINT8(input_stream); /* RootDirectory */
    Stream_Read_UINT32(input_stream, filename_length); /* FileNameLength */

    /* Convert name to UTF-8 */
    guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), filename_length/2,
            destination_path, sizeof(destination_path));

    GUAC_RDP_DEBUG(2, "[file_id=%i] destination_path=\"%s\"", file_id, destination_path);

    /* If file moving to \Download folder, start stream, do not move */
    if (strncmp(destination_path, "\\Download\\", 10) == 0) {

        guac_rdp_fs_file* file;

        /* Get file */
        file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id);
        if (file == NULL)
            return;

        /* Initiate download, pretend move succeeded */
        guac_rdpdr_start_download(device, file->absolute_path);
        output_stream = guac_rdpdr_new_io_completion(device,
                completion_id, STATUS_SUCCESS, 4);

    }

    /* Otherwise, rename as requested */
    else {

        result = guac_rdp_fs_rename((guac_rdp_fs*) device->data, file_id,
                destination_path);
        if (result < 0)
            output_stream = guac_rdpdr_new_io_completion(device,
                    completion_id, guac_rdp_fs_get_status(result), 4);
        else
            output_stream = guac_rdpdr_new_io_completion(device,
                    completion_id, STATUS_SUCCESS, 4);

    }

    Stream_Write_UINT32(output_stream, length);
    svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream);

}
Пример #2
0
static BOOL TestStream_Seek(void)
{
	BOOL rc = FALSE;
	wStream* s = Stream_New(NULL, 100);
	if (!s)
		goto out;

	if (s->pointer != s->buffer)
		goto out;

	Stream_Seek(s, 5);
	if (s->pointer != s->buffer + 5)
		goto out;
	Stream_Seek_UINT8(s);
	if (s->pointer != s->buffer + 6)
		goto out;

	Stream_Seek_UINT16(s);
	if (s->pointer != s->buffer + 8)
		goto out;

	Stream_Seek_UINT32(s);
	if (s->pointer != s->buffer + 12)
		goto out;
	Stream_Seek_UINT64(s);
	if (s->pointer != s->buffer + 20)
		goto out;

	rc = TRUE;
out:
	Stream_Free(s, TRUE);
	return rc;
}
Пример #3
0
BOOL rdp_read_share_data_header(wStream* s, UINT16* length, BYTE* type, UINT32* share_id,
					BYTE *compressed_type, UINT16 *compressed_len)
{
	if (Stream_GetRemainingLength(s) < 12)
		return FALSE;

	/* Share Data Header */
	Stream_Read_UINT32(s, *share_id); /* shareId (4 bytes) */
	Stream_Seek_UINT8(s); /* pad1 (1 byte) */
	Stream_Seek_UINT8(s); /* streamId (1 byte) */
	Stream_Read_UINT16(s, *length); /* uncompressedLength (2 bytes) */
	Stream_Read_UINT8(s, *type); /* pduType2, Data PDU Type (1 byte) */
	Stream_Read_UINT8(s, *compressed_type); /* compressedType (1 byte) */
	Stream_Read_UINT16(s, *compressed_len); /* compressedLength (2 bytes) */
	return TRUE;
}
Пример #4
0
static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s)
{
	int i;

	if (Stream_GetRemainingLength(s) < 3)
	{
		DEBUG_WARN("RfxMessageRegion packet too small");
		return FALSE;
	}

	Stream_Seek_UINT8(s); /* regionFlags (1 byte) */
	Stream_Read_UINT16(s, message->numRects); /* numRects (2 bytes) */

	if (message->numRects < 1)
	{
		/* Unfortunately, it isn't documented.
		It seems that server asks to clip whole session when numRects = 0.
		Issue: https://github.com/FreeRDP/FreeRDP/issues/1738 */

		DEBUG_WARN("no rects. Clip whole session.");
		message->numRects = 1;
		message->rects = (RFX_RECT*) realloc(message->rects, message->numRects * sizeof(RFX_RECT));
		if (!message->rects)
			return FALSE;
		message->rects->x = 0;
		message->rects->y = 0;
		message->rects->width = context->width;
		message->rects->height = context->height;

		return TRUE;
	}

	if (Stream_GetRemainingLength(s) < (size_t) (8 * message->numRects))
	{
		DEBUG_WARN("RfxMessageRegion packet too small for num_rects=%d", message->numRects);
		return FALSE;
	}

	message->rects = (RFX_RECT*) realloc(message->rects, message->numRects * sizeof(RFX_RECT));
	if (!message->rects)
		return FALSE;

	/* rects */
	for (i = 0; i < message->numRects; i++)
	{
		/* RFX_RECT */
		Stream_Read_UINT16(s, message->rects[i].x); /* x (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].y); /* y (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].width); /* width (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].height); /* height (2 bytes) */

		WLog_Print(context->priv->log, WLOG_DEBUG, "rect %d (x,y=%d,%d w,h=%d %d).", i,
				message->rects[i].x, message->rects[i].y,
				message->rects[i].width, message->rects[i].height);
	}

	return TRUE;
}
Пример #5
0
static void wts_write_drdynvc_header(wStream* s, BYTE Cmd, UINT32 ChannelId)
{
	BYTE* bm;
	int cbChId;
	Stream_GetPointer(s, bm);
	Stream_Seek_UINT8(s);
	cbChId = wts_write_variable_uint(s, ChannelId);
	*bm = ((Cmd & 0x0F) << 4) | cbChId;
}
Пример #6
0
static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *s)
{
	VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*) pChannelCallback;
	VIDEO_PLUGIN* video;
	VideoClientContext *context;
	UINT32 cbSize, packetType;
	TSMM_VIDEO_DATA data;

	video = (VIDEO_PLUGIN*) callback->plugin;
	context = (VideoClientContext *)video->wtsPlugin.pInterface;

	if (Stream_GetRemainingLength(s) < 4)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(s, cbSize);
	if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize-4))
	{
		WLog_ERR(TAG, "invalid cbSize");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT32(s, packetType);
	if (packetType != TSMM_PACKET_TYPE_VIDEO_DATA)
	{
		WLog_ERR(TAG, "only expecting VIDEO_DATA on the data channel");
		return ERROR_INVALID_DATA;
	}

	if (Stream_GetRemainingLength(s) < 32)
	{
		WLog_ERR(TAG, "not enough bytes for a TSMM_VIDEO_DATA");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT8(s, data.PresentationId);
	Stream_Read_UINT8(s, data.Version);
	Stream_Read_UINT8(s, data.Flags);
	Stream_Seek_UINT8(s); /* reserved */
	Stream_Read_UINT64(s, data.hnsTimestamp);
	Stream_Read_UINT64(s, data.hnsDuration);
	Stream_Read_UINT16(s, data.CurrentPacketIndex);
	Stream_Read_UINT16(s, data.PacketsInSample);
	Stream_Read_UINT32(s, data.SampleNumber);
	Stream_Read_UINT32(s, data.cbSample);
	data.pSample = Stream_Pointer(s);

/*
	WLog_DBG(TAG, "videoData: id:%"PRIu8" version:%"PRIu8" flags:0x%"PRIx8" timestamp=%"PRIu64" duration=%"PRIu64
			" curPacketIndex:%"PRIu16" packetInSample:%"PRIu16" sampleNumber:%"PRIu32" cbSample:%"PRIu32"",
			data.PresentationId, data.Version, data.Flags, data.hnsTimestamp, data.hnsDuration,
			data.CurrentPacketIndex, data.PacketsInSample, data.SampleNumber, data.cbSample);
*/

	return video_VideoData(context, &data);
}
Пример #7
0
BOOL update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color)
{
	if (Stream_GetRemainingLength(s) < 14)
		return FALSE;

	Stream_Read_UINT16(s, pointer_color->cacheIndex); /* cacheIndex (2 bytes) */
	Stream_Read_UINT16(s, pointer_color->xPos); /* xPos (2 bytes) */
	Stream_Read_UINT16(s, pointer_color->yPos); /* yPos (2 bytes) */
	Stream_Read_UINT16(s, pointer_color->width); /* width (2 bytes) */
	Stream_Read_UINT16(s, pointer_color->height); /* height (2 bytes) */
	Stream_Read_UINT16(s, pointer_color->lengthAndMask); /* lengthAndMask (2 bytes) */
	Stream_Read_UINT16(s, pointer_color->lengthXorMask); /* lengthXorMask (2 bytes) */

	/**
	 * There does not seem to be any documentation on why
	 * xPos / yPos can be larger than width / height
	 * so it is missing in documentation or a bug in implementation
	 * 2.2.9.1.1.4.4 Color Pointer Update (TS_COLORPOINTERATTRIBUTE)
	 */
	if (pointer_color->xPos >= pointer_color->width)
		pointer_color->xPos = 0;
	if (pointer_color->yPos >= pointer_color->height)
		pointer_color->yPos = 0;

	if (pointer_color->lengthXorMask > 0)
	{
		if (Stream_GetRemainingLength(s) < pointer_color->lengthXorMask)
			return FALSE;

		if (!pointer_color->xorMaskData)
			pointer_color->xorMaskData = malloc(pointer_color->lengthXorMask);
		else
			pointer_color->xorMaskData = realloc(pointer_color->xorMaskData, pointer_color->lengthXorMask);

		Stream_Read(s, pointer_color->xorMaskData, pointer_color->lengthXorMask);
	}

	if (pointer_color->lengthAndMask > 0)
	{
		if (Stream_GetRemainingLength(s) < pointer_color->lengthAndMask)
			return FALSE;

		if (!pointer_color->andMaskData)
			pointer_color->andMaskData = malloc(pointer_color->lengthAndMask);
		else
			pointer_color->andMaskData = realloc(pointer_color->andMaskData, pointer_color->lengthAndMask);

		Stream_Read(s, pointer_color->andMaskData, pointer_color->lengthAndMask);
	}

	if (Stream_GetRemainingLength(s) > 0)
		Stream_Seek_UINT8(s); /* pad (1 byte) */

	return TRUE;
}
Пример #8
0
BOOL nego_read_request(rdpNego* nego, wStream* s)
{
	BYTE li;
	BYTE c;
	BYTE type;

	tpkt_read_header(s);

	if (!tpdu_read_connection_request(s, &li))
		return FALSE;

	if (li != Stream_GetRemainingLength(s) + 6)
	{
		fprintf(stderr, "Incorrect TPDU length indicator.\n");
		return FALSE;
	}

	if (Stream_GetRemainingLength(s) > 8)
	{
		/* Optional routingToken or cookie, ending with CR+LF */
		while (Stream_GetRemainingLength(s) > 0)
		{
			Stream_Read_UINT8(s, c);

			if (c != '\x0D')
				continue;

			Stream_Peek_UINT8(s, c);

			if (c != '\x0A')
				continue;

			Stream_Seek_UINT8(s);
			break;
		}
	}

	if (Stream_GetRemainingLength(s) >= 8)
	{
		/* rdpNegData (optional) */

		Stream_Read_UINT8(s, type); /* Type */

		if (type != TYPE_RDP_NEG_REQ)
		{
			fprintf(stderr, "Incorrect negotiation request type %d\n", type);
			return FALSE;
		}

		nego_process_negotiation_request(nego, s);
	}

	return TRUE;
}
Пример #9
0
void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin,
                                 wStream* input_stream) {

    guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
    guac_rdpsnd_pdu_header header;

    /* Get audio stream from plugin */
    audio_stream* audio = rdpsnd->audio;

    /* Read RDPSND PDU header */
    Stream_Read_UINT8(input_stream, header.message_type);
    Stream_Seek_UINT8(input_stream);
    Stream_Read_UINT16(input_stream, header.body_size);

    /*
     * If next PDU is SNDWAVE (due to receiving WaveInfo PDU previously),
     * ignore the header and parse as a Wave PDU.
     */
    if (rdpsnd->next_pdu_is_wave) {
        guac_rdpsnd_wave_handler(rdpsnd, audio, input_stream, &header);
        return;
    }

    /* Dispatch message to standard handlers */
    switch (header.message_type) {

    /* Server Audio Formats and Version PDU */
    case SNDC_FORMATS:
        guac_rdpsnd_formats_handler(rdpsnd, audio,
                                    input_stream, &header);
        break;

    /* Training PDU */
    case SNDC_TRAINING:
        guac_rdpsnd_training_handler(rdpsnd, audio,
                                     input_stream, &header);
        break;

    /* WaveInfo PDU */
    case SNDC_WAVE:
        guac_rdpsnd_wave_info_handler(rdpsnd, audio,
                                      input_stream, &header);
        break;

    /* Close PDU */
    case SNDC_CLOSE:
        guac_rdpsnd_close_handler(rdpsnd, audio,
                                  input_stream, &header);
        break;

    }

}
Пример #10
0
static BOOL rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s)
{
	UINT16 timestamp = 0;
	BYTE confirmBlockNum = 0;

	if (Stream_GetRemainingLength(s) < 4)
		return FALSE;

	Stream_Read_UINT16(s, timestamp);
	Stream_Read_UINT8(s, confirmBlockNum);
	Stream_Seek_UINT8(s);
	return TRUE;
}
Пример #11
0
static void wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, UINT32 length)
{
	UINT16 Version;

	if (length < 3)
		return;

	Stream_Seek_UINT8(channel->receiveData); /* Pad (1 byte) */
	Stream_Read_UINT16(channel->receiveData, Version);

	DEBUG_DVC("Version: %d", Version);

	channel->vcm->drdynvc_state = DRDYNVC_STATE_READY;
}
Пример #12
0
static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s)
{
	int i;

	if (Stream_GetRemainingLength(s) < 3)
	{
		DEBUG_WARN("RfxMessageRegion packet too small");
		return FALSE;
	}

	Stream_Seek_UINT8(s); /* regionFlags (1 byte) */
	Stream_Read_UINT16(s, message->num_rects); /* numRects (2 bytes) */

	if (message->num_rects < 1)
	{
		DEBUG_WARN("no rects.");
		return TRUE;
	}

	if (Stream_GetRemainingLength(s) < 8 * message->num_rects)
	{
		DEBUG_WARN("RfxMessageRegion packet too small for num_rects=%d", message->num_rects);
		return FALSE;
	}

	if (message->rects != NULL)
		message->rects = (RFX_RECT*) realloc(message->rects, message->num_rects * sizeof(RFX_RECT));
	else
		message->rects = (RFX_RECT*) malloc(message->num_rects * sizeof(RFX_RECT));

	/* rects */
	for (i = 0; i < message->num_rects; i++)
	{
		/* RFX_RECT */
		Stream_Read_UINT16(s, message->rects[i].x); /* x (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].y); /* y (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].width); /* width (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].height); /* height (2 bytes) */

		DEBUG_RFX("rect %d (%d %d %d %d).",
			i, message->rects[i].x, message->rects[i].y, message->rects[i].width, message->rects[i].height);
	}
	return TRUE;
}
Пример #13
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s)
{
	UINT16 timestamp;
	BYTE confirmBlockNum;
	UINT error = CHANNEL_RC_OK;

	if (Stream_GetRemainingLength(s) < 4)
	{
		WLog_ERR(TAG, "not enought data in stream!");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT16(s, timestamp);
	Stream_Read_UINT8(s, confirmBlockNum);
	Stream_Seek_UINT8(s);

	IFCALLRET(context->ConfirmBlock, error,  context, confirmBlockNum, timestamp);
	if (error)
		WLog_ERR(TAG, "context->ConfirmBlock failed with error %lu", error);

	return error;
}
Пример #14
0
BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length, PULONG pBytesWritten)
{
	wStream* s;
	int cbLen;
	int cbChId;
	int first;
	BYTE* buffer;
	UINT32 length;
	UINT32 written;
	rdpPeerChannel* channel = (rdpPeerChannel*) hChannelHandle;

	if (!channel)
		return FALSE;

	if (channel->channelType == RDP_PEER_CHANNEL_TYPE_SVC)
	{
		length = Length;
		buffer = (BYTE*) malloc(length);
		CopyMemory(buffer, Buffer, length);

		wts_queue_send_item(channel, buffer, length);
	}
	else if (!channel->vcm->drdynvc_channel || (channel->vcm->drdynvc_state != DRDYNVC_STATE_READY))
	{
		DEBUG_DVC("drdynvc not ready");
		return FALSE;
	}
	else
	{
		first = TRUE;

		while (Length > 0)
		{
			s = Stream_New(NULL, channel->client->settings->VirtualChannelChunkSize);
			buffer = Stream_Buffer(s);

			Stream_Seek_UINT8(s);
			cbChId = wts_write_variable_uint(s, channel->channelId);

			if (first && (Length > (UINT32) Stream_GetRemainingLength(s)))
			{
				cbLen = wts_write_variable_uint(s, Length);
				buffer[0] = (DATA_FIRST_PDU << 4) | (cbLen << 2) | cbChId;
			}
			else
			{
				buffer[0] = (DATA_PDU << 4) | cbChId;
			}

			first = FALSE;
			written = Stream_GetRemainingLength(s);

			if (written > Length)
				written = Length;

			Stream_Write(s, Buffer, written);
			length = Stream_GetPosition(s);
			Stream_Free(s, FALSE);

			Length -= written;
			Buffer += written;

			wts_queue_send_item(channel->vcm->drdynvc_channel, buffer, length);
		}
	}

	if (pBytesWritten)
		*pBytesWritten = Length;

	return TRUE;
}
Пример #15
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
{
	int i, num_known_format = 0;
	UINT32 flags, vol, pitch;
	UINT16 udpPort;
	BYTE lastblock;
	UINT error = CHANNEL_RC_OK;

	if (Stream_GetRemainingLength(s) < 20)
	{
		WLog_ERR(TAG, "not enought data in stream!");
		return ERROR_INVALID_DATA;
	}

	Stream_Read_UINT32(s, flags); /* dwFlags */
	Stream_Read_UINT32(s, vol); /* dwVolume */
	Stream_Read_UINT32(s, pitch); /* dwPitch */
	Stream_Read_UINT16(s, udpPort); /* wDGramPort */
	Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
	Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
	Stream_Read_UINT16(s, context->clientVersion); /* wVersion */
	Stream_Seek_UINT8(s); /* bPad */

	/* this check is only a guess as cbSize can influence the size of a format record */
	if (Stream_GetRemainingLength(s) < context->num_client_formats * 18)
	{
		WLog_ERR(TAG, "not enought data in stream!");
		return ERROR_INVALID_DATA;
	}

	if (!context->num_client_formats)
	{
		WLog_ERR(TAG,  "client doesn't support any format!");
		return ERROR_INTERNAL_ERROR;
	}

	context->client_formats = (AUDIO_FORMAT *)calloc(context->num_client_formats, sizeof(AUDIO_FORMAT));
	if (!context->client_formats)
	{
		WLog_ERR(TAG,  "calloc failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	for (i = 0; i < context->num_client_formats; i++)
	{
		if (Stream_GetRemainingLength(s) < 18)
		{
			WLog_ERR(TAG, "not enought data in stream!");
			error = ERROR_INVALID_DATA;
			goto out_free;
		}


		Stream_Read_UINT16(s, context->client_formats[i].wFormatTag);
		Stream_Read_UINT16(s, context->client_formats[i].nChannels);
		Stream_Read_UINT32(s, context->client_formats[i].nSamplesPerSec);
		Stream_Read_UINT32(s, context->client_formats[i].nAvgBytesPerSec);
		Stream_Read_UINT16(s, context->client_formats[i].nBlockAlign);
		Stream_Read_UINT16(s, context->client_formats[i].wBitsPerSample);
		Stream_Read_UINT16(s, context->client_formats[i].cbSize);

		if (context->client_formats[i].cbSize > 0)
		{
			if (!Stream_SafeSeek(s, context->client_formats[i].cbSize))
			{
				WLog_ERR(TAG, "Stream_SafeSeek failed!");
				error = ERROR_INTERNAL_ERROR;
				goto out_free;
			}

		}

		if (context->client_formats[i].wFormatTag != 0)
		{
			//lets call this a known format
			//TODO: actually look through our own list of known formats
			num_known_format++;
		}
	}

	if (!context->num_client_formats)
	{
		WLog_ERR(TAG,  "client doesn't support any known format!");
		goto out_free;
	}

	return CHANNEL_RC_OK;

out_free:
	free(context->client_formats);
	return error;
}
Пример #16
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
UINT rdpsnd_server_handle_messages(RdpsndServerContext *context)
{
	DWORD bytesReturned;
	UINT ret = CHANNEL_RC_OK;

	RdpsndServerPrivate *priv = context->priv;
	wStream *s = priv->input_stream;

	if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned))
	{
		if (GetLastError() == ERROR_NO_DATA)
			return ERROR_NO_DATA;

		WLog_ERR(TAG,  "channel connection closed");
		return ERROR_INTERNAL_ERROR;
	}
	priv->expectedBytes -= bytesReturned;
	Stream_Seek(s, bytesReturned);

	if (priv->expectedBytes)
		return CHANNEL_RC_OK;

	Stream_SealLength(s);
	Stream_SetPosition(s, 0);
	if (priv->waitingHeader)
	{
		/* header case */
		Stream_Read_UINT8(s, priv->msgType);
		Stream_Seek_UINT8(s); /* bPad */
		Stream_Read_UINT16(s, priv->expectedBytes);

		priv->waitingHeader = FALSE;
		Stream_SetPosition(s, 0);
		if (priv->expectedBytes)
		{
			if (!Stream_EnsureCapacity(s, priv->expectedBytes))
			{
				WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
				return CHANNEL_RC_NO_MEMORY;
			}
			return CHANNEL_RC_OK;
		}
	}

	/* when here we have the header + the body */
#ifdef WITH_DEBUG_SND
	WLog_DBG(TAG,  "message type %d", priv->msgType);
#endif
	priv->expectedBytes = 4;
	priv->waitingHeader = TRUE;

	switch (priv->msgType)
	{
		case SNDC_WAVECONFIRM:
			ret = rdpsnd_server_recv_waveconfirm(context, s);
			break;

		case SNDC_FORMATS:
			ret = rdpsnd_server_recv_formats(context, s);

			if ((ret == CHANNEL_RC_OK) && (context->clientVersion < 6))
				IFCALL(context->Activated, context);

			break;

		case SNDC_QUALITYMODE:
			ret = rdpsnd_server_recv_quality_mode(context, s);
			Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */

			if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= 6))
				IFCALL(context->Activated, context);
			break;

		default:
			WLog_ERR(TAG,  "UNKOWN MESSAGE TYPE!! (%#0X)", priv->msgType);
			ret = ERROR_INVALID_DATA;
			break;
	}
	Stream_SetPosition(s, 0);

	return ret;
}
Пример #17
0
BOOL rdpsnd_server_handle_messages(RdpsndServerContext *context)
{
	DWORD bytesReturned;
	BOOL ret;

	RdpsndServerPrivate *priv = context->priv;
	wStream *s = priv->input_stream;

	if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned))
	{
		if (GetLastError() == ERROR_NO_DATA)
			return TRUE;

		CLOG_ERR( "%s: channel connection closed\n", __FUNCTION__);
		return FALSE;
	}
	priv->expectedBytes -= bytesReturned;
	Stream_Seek(s, bytesReturned);

	if (priv->expectedBytes)
		return TRUE;

	Stream_SetPosition(s, 0);
	if (priv->waitingHeader)
	{
		/* header case */
		Stream_Read_UINT8(s, priv->msgType);
		Stream_Seek_UINT8(s); /* bPad */
		Stream_Read_UINT16(s, priv->expectedBytes);

		priv->waitingHeader = FALSE;
		Stream_SetPosition(s, 0);
		if (priv->expectedBytes)
		{
			Stream_EnsureCapacity(s, priv->expectedBytes);
			return TRUE;
		}
	}

	/* when here we have the header + the body */
#ifdef WITH_DEBUG_SND
	CLOG_ERR( "%s: message type %d\n", __FUNCTION__, priv->msgType);
#endif
	priv->expectedBytes = 4;
	priv->waitingHeader = TRUE;

	switch (priv->msgType)
	{
		case SNDC_WAVECONFIRM:
			ret = rdpsnd_server_recv_waveconfirm(context, s);
			break;

		case SNDC_FORMATS:
			ret = rdpsnd_server_recv_formats(context, s);
			break;

		case SNDC_QUALITYMODE:
			ret = rdpsnd_server_recv_quality_mode(context, s);
			Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */

			if (ret)
			{
				IFCALL(context->Activated, context);
			}
			break;

		default:
			CLOG_ERR( "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, priv->msgType);
			ret = FALSE;
			break;
	}
	Stream_SetPosition(s, 0);

	return ret;
}
Пример #18
0
static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s, UINT16* pExpectedBlockType)
{
	int i;
	UINT16 regionType;
	UINT16 numTileSets;

	if (*pExpectedBlockType != WBT_REGION)
	{
		WLog_ERR(TAG, "%s: message unexpeced", __FUNCTION__);
		return FALSE;
	}
	*pExpectedBlockType = WBT_EXTENSION;

	if (Stream_GetRemainingLength(s) < 3)
	{
		WLog_ERR(TAG, "%s: packet too small (regionFlags/numRects)", __FUNCTION__);
		return FALSE;
	}

	Stream_Seek_UINT8(s); /* regionFlags (1 byte) */
	Stream_Read_UINT16(s, message->numRects); /* numRects (2 bytes) */

	if (message->numRects < 1)
	{
		/*
		   If numRects is zero the decoder must generate a rectangle with
		   coordinates (0, 0, width, height).
		   See [MS-RDPRFX] (revision >= 17.0) 2.2.2.3.3 TS_RFX_REGION
		   https://msdn.microsoft.com/en-us/library/ff635233.aspx
		*/

		if (!(message->rects = (RFX_RECT*) malloc(sizeof(RFX_RECT))))
			return FALSE;

		message->numRects = 1;
		message->rects->x = 0;
		message->rects->y = 0;
		message->rects->width = context->width;
		message->rects->height = context->height;

		return TRUE;
	}

	if (Stream_GetRemainingLength(s) < (size_t) (8 * message->numRects))
	{
		WLog_ERR(TAG, "%s: packet too small for num_rects=%d", __FUNCTION__, message->numRects);
		return FALSE;
	}

	if (!(message->rects = (RFX_RECT*) calloc(message->numRects, sizeof(RFX_RECT))))
		return FALSE;

	/* rects */
	for (i = 0; i < message->numRects; i++)
	{
		/* RFX_RECT */
		Stream_Read_UINT16(s, message->rects[i].x); /* x (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].y); /* y (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].width); /* width (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].height); /* height (2 bytes) */

		WLog_Print(context->priv->log, WLOG_DEBUG, "rect %d (x,y=%d,%d w,h=%d %d).", i,
				message->rects[i].x, message->rects[i].y,
				message->rects[i].width, message->rects[i].height);
	}

	if (Stream_GetRemainingLength(s) < 4)
	{
		WLog_ERR(TAG, "%s: packet too small (regionType/numTileSets)", __FUNCTION__);
		return FALSE;
	}

	Stream_Read_UINT16(s, regionType); /* regionType (2 bytes): MUST be set to CBT_REGION (0xCAC1) */
	Stream_Read_UINT16(s, numTileSets); /* numTilesets (2 bytes): MUST be set to 0x0001. */

	if (regionType != CBT_REGION)
	{
		WLog_ERR(TAG, "%s: invalid region type 0x%04X", __FUNCTION__, regionType);
		return TRUE;
	}

	if (numTileSets != 0x0001)
	{
		WLog_ERR(TAG, "%s: invalid number of tilesets (%u)", __FUNCTION__, numTileSets);
		return FALSE;
	}

	return TRUE;
}
Пример #19
0
BOOL gcc_read_client_core_data(wStream* s, rdpSettings* settings, UINT16 blockLength)
{
	char* str = NULL;
	UINT32 version;
	UINT32 color_depth;
	UINT16 colorDepth = 0;
	UINT16 postBeta2ColorDepth = 0;
	UINT16 highColorDepth = 0;
	UINT16 supportedColorDepths = 0;
	UINT32 serverSelectedProtocol = 0;

	/* Length of all required fields, until imeFileName */
	if (blockLength < 128)
		return FALSE;

	Stream_Read_UINT32(s, version); /* version */
	settings->RdpVersion = (version == RDP_VERSION_4 ? 4 : 7);

	Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth */
	Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight */
	Stream_Read_UINT16(s, colorDepth); /* ColorDepth */
	Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) */
	Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout */
	Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild */

	/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
	ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL);
	Stream_Seek(s, 32);
	sprintf_s(settings->ClientHostname, 31, "%s", str);
	settings->ClientHostname[31] = 0;
	free(str);
	str = NULL;

	Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType */
	Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType */
	Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey */

	Stream_Seek(s, 64); /* imeFileName */

	blockLength -= 128;

	/**
	 * The following fields are all optional. If one field is present, all of the preceding
	 * fields MUST also be present. If one field is not present, all of the subsequent fields
	 * MUST NOT be present.
	 * We must check the bytes left before reading each field.
	 */

	do
	{
		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth */
		blockLength -= 2;

		if (blockLength < 2)
			break;
		Stream_Seek_UINT16(s); /* clientProductID */
		blockLength -= 2;

		if (blockLength < 4)
			break;
		Stream_Seek_UINT32(s); /* serialNumber */
		blockLength -= 4;

		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, highColorDepth); /* highColorDepth */
		blockLength -= 2;

		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, supportedColorDepths); /* supportedColorDepths */
		blockLength -= 2;

		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */
		blockLength -= 2;

		if (blockLength < 64)
			break;

		ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL);
		Stream_Seek(s, 64);
		sprintf_s(settings->ClientProductId, 32, "%s", str);
		free(str);
		blockLength -= 64;

		if (blockLength < 1)
			break;
		Stream_Read_UINT8(s, settings->PerformanceFlags); /* connectionType */
		blockLength -= 1;

		if (blockLength < 1)
			break;
		Stream_Seek_UINT8(s); /* pad1octet */
		blockLength -= 1;

		if (blockLength < 4)
			break;
		Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol */
		blockLength -= 4;

		if (settings->SelectedProtocol != serverSelectedProtocol)
			return FALSE;
	} while (0);

	if (highColorDepth > 0)
	{
		if (settings->EarlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION)
			color_depth = 32;
		else
			color_depth = highColorDepth;
	}
	else if (postBeta2ColorDepth > 0)
	{
		switch (postBeta2ColorDepth)
		{
			case RNS_UD_COLOR_4BPP:
				color_depth = 4;
				break;
			case RNS_UD_COLOR_8BPP:
				color_depth = 8;
				break;
			case RNS_UD_COLOR_16BPP_555:
				color_depth = 15;
				break;
			case RNS_UD_COLOR_16BPP_565:
				color_depth = 16;
				break;
			case RNS_UD_COLOR_24BPP:
				color_depth = 24;
				break;
			default:
				return FALSE;
		}
	}
	else
	{
		switch (colorDepth)
		{
			case RNS_UD_COLOR_4BPP:
				color_depth = 4;
				break;
			case RNS_UD_COLOR_8BPP:
				color_depth = 8;
				break;
			default:
				return FALSE;
		}
	}

	/*
	 * If we are in server mode, accept client's color depth only if
	 * it is smaller than ours. This is what Windows server does.
	 */
	if ((color_depth < settings->ColorDepth) || !settings->ServerMode)
		settings->ColorDepth = color_depth;

	return TRUE;
}
Пример #20
0
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input)
{
	char* s = NULL;
	mode_t m;
	UINT64 size;
	int status;
	char* fullpath;
	struct STAT st;
#if defined(__linux__) && !defined(ANDROID) || defined(sun)
	struct timespec tv[2];
#else
	struct timeval tv[2];
#endif
	UINT64 LastWriteTime;
	UINT32 FileAttributes;
	UINT32 FileNameLength;

	m = 0;

	switch (FsInformationClass)
	{
		case FileBasicInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
			Stream_Seek_UINT64(input); /* CreationTime */
			Stream_Seek_UINT64(input); /* LastAccessTime */
			Stream_Read_UINT64(input, LastWriteTime);
			Stream_Seek_UINT64(input); /* ChangeTime */
			Stream_Read_UINT32(input, FileAttributes);

			if (FSTAT(file->fd, &st) != 0)
				return FALSE;

			tv[0].tv_sec = st.st_atime;
			tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
#ifndef WIN32
			/* TODO on win32 */
#ifdef ANDROID
			tv[0].tv_usec = 0;
			tv[1].tv_usec = 0;
			utimes(file->fullpath, tv);
#elif defined (__linux__) || defined (sun)
			tv[0].tv_nsec = 0;
			tv[1].tv_nsec = 0;			
			futimens(file->fd, tv);
#else
			tv[0].tv_usec = 0;
			tv[1].tv_usec = 0;
			futimes(file->fd, tv);
#endif

			if (FileAttributes > 0)
			{
				m = st.st_mode;
				if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
					m |= S_IWUSR;
				else
					m &= ~S_IWUSR;
				if (m != st.st_mode)
					fchmod(file->fd, st.st_mode);
			}
#endif
			break;

		case FileEndOfFileInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
		case FileAllocationInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
			Stream_Read_UINT64(input, size);
#ifndef _WIN32
			if (ftruncate(file->fd, size) != 0)
				return FALSE;
#endif
			break;

		case FileDispositionInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
			/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
			if (file->is_dir && !dir_empty(file->fullpath))
				break;

			if (Length)
				Stream_Read_UINT8(input, file->delete_pending);
			else
				file->delete_pending = 1;
			break;

		case FileRenameInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
			Stream_Seek_UINT8(input); /* ReplaceIfExists */
			Stream_Seek_UINT8(input); /* RootDirectory */
			Stream_Read_UINT32(input, FileNameLength);

			status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input),
					FileNameLength / 2, &s, 0, NULL, NULL);

			if (status < 1)
				if (!(s = (char*) calloc(1, 1)))
				{
					WLog_ERR(TAG, "calloc failed!");
					return FALSE;
				}

			fullpath = drive_file_combine_fullpath(file->basepath, s);
			if (!fullpath)
			{
				WLog_ERR(TAG, "drive_file_combine_fullpath failed!");
				free (s);
				return FALSE;
			}
			free(s);

#ifdef _WIN32
			if (file->fd)
				close(file->fd);
#endif
			if (rename(file->fullpath, fullpath) == 0)
			{
				drive_file_set_fullpath(file, fullpath);
#ifdef _WIN32
				file->fd = OPEN(fullpath, O_RDWR | O_BINARY);
#endif
			}
			else
			{
				free(fullpath);
				return FALSE;
			}

			break;

		default:
			return FALSE;
	}

	return TRUE;
}
Пример #21
0
void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
        wStream* input_stream, guac_rdpsnd_pdu_header* header) {

    int server_format_count;
    int server_version;
    int i;

    wStream* output_stream;
    int output_body_size;
    unsigned char* output_stream_end;

    /* Get associated client data */
    guac_client* client = rdpsnd->client;
    guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;

    /* Get audio stream from client data */
    guac_audio_stream* audio = rdp_client->audio;

    /* Format header */
    Stream_Seek(input_stream, 14);
    Stream_Read_UINT16(input_stream, server_format_count);
    Stream_Seek_UINT8(input_stream);
    Stream_Read_UINT16(input_stream, server_version);
    Stream_Seek_UINT8(input_stream);

    /* Initialize Client Audio Formats and Version PDU */
    output_stream = Stream_New(NULL, 24);
    Stream_Write_UINT8(output_stream,  SNDC_FORMATS);
    Stream_Write_UINT8(output_stream,  0);

    /* Fill in body size later */
    Stream_Seek_UINT16(output_stream); /* offset = 0x02 */

    /* Flags, volume, and pitch */
    Stream_Write_UINT32(output_stream, TSSNDCAPS_ALIVE);
    Stream_Write_UINT32(output_stream, 0);
    Stream_Write_UINT32(output_stream, 0);

    /* Datagram port (UDP) */
    Stream_Write_UINT16(output_stream, 0);

    /* Fill in format count later */
    Stream_Seek_UINT16(output_stream); /* offset = 0x12 */

    /* Version and padding */
    Stream_Write_UINT8(output_stream,  0);
    Stream_Write_UINT16(output_stream, 6);
    Stream_Write_UINT8(output_stream,  0);

    /* Check each server format, respond if supported and audio is enabled */
    if (audio != NULL) {
        for (i=0; i < server_format_count; i++) {

            unsigned char* format_start;

            int format_tag;
            int channels;
            int rate;
            int bps;
            int body_size;

            /* Remember position in stream */
            Stream_GetPointer(input_stream, format_start);

            /* Read format */
            Stream_Read_UINT16(input_stream, format_tag);
            Stream_Read_UINT16(input_stream, channels);
            Stream_Read_UINT32(input_stream, rate);
            Stream_Seek_UINT32(input_stream);
            Stream_Seek_UINT16(input_stream);
            Stream_Read_UINT16(input_stream, bps);

            /* Skip past extra data */
            Stream_Read_UINT16(input_stream, body_size);
            Stream_Seek(input_stream, body_size);

            /* If PCM, accept */
            if (format_tag == WAVE_FORMAT_PCM) {

                /* If can fit another format, accept it */
                if (rdpsnd->format_count < GUAC_RDP_MAX_FORMATS) {

                    /* Add channel */
                    int current = rdpsnd->format_count++;
                    rdpsnd->formats[current].rate     = rate;
                    rdpsnd->formats[current].channels = channels;
                    rdpsnd->formats[current].bps      = bps;

                    /* Log format */
                    guac_client_log(client, GUAC_LOG_INFO,
                            "Accepted format: %i-bit PCM with %i channels at "
                            "%i Hz",
                            bps, channels, rate);

                    /* Ensure audio stream is configured to use accepted
                     * format */
                    guac_audio_stream_reset(audio, NULL, rate, channels, bps);

                    /* Queue format for sending as accepted */
                    Stream_EnsureRemainingCapacity(output_stream,
                            18 + body_size);
                    Stream_Write(output_stream, format_start, 18 + body_size);

                    /*
                     * BEWARE that using Stream_EnsureRemainingCapacity means
                     * that any pointers returned via Stream_GetPointer on
                     * output_stream are invalid.
                     */

                }

                /* Otherwise, log that we dropped one */
                else
                    guac_client_log(client, GUAC_LOG_INFO,
                            "Dropped valid format: %i-bit PCM with %i "
                            "channels at %i Hz",
                            bps, channels, rate);

            }

        }
    }

    /* Otherwise, ignore all supported formats as we do not intend to actually
     * receive audio */
    else
        guac_client_log(client, GUAC_LOG_DEBUG,
                "Audio explicitly disabled. Ignoring supported formats.");

    /* Calculate size of PDU */
    output_body_size = Stream_GetPosition(output_stream) - 4;
    Stream_GetPointer(output_stream, output_stream_end);

    /* Set body size */
    Stream_SetPosition(output_stream, 0x02);
    Stream_Write_UINT16(output_stream, output_body_size);

    /* Set format count */
    Stream_SetPosition(output_stream, 0x12);
    Stream_Write_UINT16(output_stream, rdpsnd->format_count);

    /* Reposition cursor at end (necessary for message send) */
    Stream_SetPointer(output_stream, output_stream_end);

    /* Send accepted formats */
    pthread_mutex_lock(&(rdp_client->rdp_lock));
    svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);

    /* If version greater than 6, must send Quality Mode PDU */
    if (server_version >= 6) {

        /* Always send High Quality for now */
        output_stream = Stream_New(NULL, 8);
        Stream_Write_UINT8(output_stream, SNDC_QUALITYMODE);
        Stream_Write_UINT8(output_stream, 0);
        Stream_Write_UINT16(output_stream, 4);
        Stream_Write_UINT16(output_stream, HIGH_QUALITY);
        Stream_Write_UINT16(output_stream, 0);

        svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
    }

    pthread_mutex_unlock(&(rdp_client->rdp_lock));

}
Пример #22
0
Файл: rfx.c Проект: C4rt/FreeRDP
static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s, UINT16* pExpecedBlockType)
{
	BOOL rc;
	int i, close_cnt;
	int pos;
	BYTE quant;
	RFX_TILE* tile;
	UINT32* quants;
	UINT16 subtype;
	UINT32 blockLen;
	UINT32 blockType;
	UINT32 tilesDataSize;
	PTP_WORK* work_objects = NULL;
	RFX_TILE_PROCESS_WORK_PARAM* params = NULL;
	void *pmem;

	if (*pExpecedBlockType != WBT_EXTENSION)
	{
		WLog_ERR(TAG, "%s: message unexpeced", __FUNCTION__);
		return FALSE;
	}
	*pExpecedBlockType = WBT_FRAME_END;

	if (Stream_GetRemainingLength(s) < 14)
	{
		WLog_ERR(TAG, "RfxMessageTileSet packet too small");
		return FALSE;
	}

	Stream_Read_UINT16(s, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */

	if (subtype != CBT_TILESET)
	{
		WLog_ERR(TAG, "invalid subtype, expected CBT_TILESET.");
		return FALSE;
	}

	Stream_Seek_UINT16(s); /* idx (2 bytes), must be set to 0x0000 */
	Stream_Seek_UINT16(s); /* properties (2 bytes) */

	Stream_Read_UINT8(s, context->numQuant); /* numQuant (1 byte) */
	Stream_Seek_UINT8(s); /* tileSize (1 byte), must be set to 0x40 */

	if (context->numQuant < 1)
	{
		WLog_ERR(TAG, "no quantization value.");
		return FALSE;
	}

	Stream_Read_UINT16(s, message->numTiles); /* numTiles (2 bytes) */

	if (message->numTiles < 1)
	{
		WLog_ERR(TAG, "no tiles.");
		return FALSE;
	}

	Stream_Read_UINT32(s, tilesDataSize); /* tilesDataSize (4 bytes) */

	if (!(pmem = realloc((void*) context->quants, context->numQuant * 10 * sizeof(UINT32))))
		return FALSE;

	quants = context->quants = (UINT32*) pmem;

	/* quantVals */
	if (Stream_GetRemainingLength(s) < (size_t) (context->numQuant * 5))
	{
		WLog_ERR(TAG, "RfxMessageTileSet packet too small for num_quants=%d", context->numQuant);
		return FALSE;
	}

	for (i = 0; i < context->numQuant; i++)
	{
		/* RFX_CODEC_QUANT */
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);

		WLog_Print(context->priv->log, WLOG_DEBUG, "quant %d (%d %d %d %d %d %d %d %d %d %d).",
			i, context->quants[i * 10], context->quants[i * 10 + 1],
			context->quants[i * 10 + 2], context->quants[i * 10 + 3],
			context->quants[i * 10 + 4], context->quants[i * 10 + 5],
			context->quants[i * 10 + 6], context->quants[i * 10 + 7],
			context->quants[i * 10 + 8], context->quants[i * 10 + 9]);
	}

	if (!(message->tiles = (RFX_TILE**) calloc(message->numTiles, sizeof(RFX_TILE*))))
	{
		message->numTiles = 0;
		return FALSE;
	}

	if (context->priv->UseThreads)
	{
		work_objects = (PTP_WORK*) calloc(message->numTiles, sizeof(PTP_WORK));
		params = (RFX_TILE_PROCESS_WORK_PARAM*) calloc(message->numTiles, sizeof(RFX_TILE_PROCESS_WORK_PARAM));

		if (!work_objects)
		{
			free(params);
			return FALSE;
		}

		if (!params)
		{
			free(work_objects);
			return FALSE;
		}
	}

	/* tiles */
	close_cnt = 0;
	rc = TRUE;
	for (i = 0; i < message->numTiles; i++)
	{
		if (!(tile = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool)))
		{
			WLog_ERR(TAG, "RfxMessageTileSet failed to get tile from object pool");
			rc = FALSE;
			break;
		}

		message->tiles[i] = tile;

		/* RFX_TILE */
		if (Stream_GetRemainingLength(s) < 6)
		{
			WLog_ERR(TAG, "RfxMessageTileSet packet too small to read tile %d/%d", i, message->numTiles);
			rc = FALSE;
			break;
		}

		Stream_Read_UINT16(s, blockType); /* blockType (2 bytes), must be set to CBT_TILE (0xCAC3) */
		Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */

		if (Stream_GetRemainingLength(s) < blockLen - 6)
		{
			WLog_ERR(TAG, "RfxMessageTileSet not enough bytes to read tile %d/%d with blocklen=%d",
					 i, message->numTiles, blockLen);
			rc = FALSE;
			break;
		}

		pos = Stream_GetPosition(s) - 6 + blockLen;

		if (blockType != CBT_TILE)
		{
			WLog_ERR(TAG, "unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType);
			rc = FALSE;
			break;
		}

		Stream_Read_UINT8(s, tile->quantIdxY); /* quantIdxY (1 byte) */
		Stream_Read_UINT8(s, tile->quantIdxCb); /* quantIdxCb (1 byte) */
		Stream_Read_UINT8(s, tile->quantIdxCr); /* quantIdxCr (1 byte) */
		Stream_Read_UINT16(s, tile->xIdx); /* xIdx (2 bytes) */
		Stream_Read_UINT16(s, tile->yIdx); /* yIdx (2 bytes) */
		Stream_Read_UINT16(s, tile->YLen); /* YLen (2 bytes) */
		Stream_Read_UINT16(s, tile->CbLen); /* CbLen (2 bytes) */
		Stream_Read_UINT16(s, tile->CrLen); /* CrLen (2 bytes) */

		Stream_GetPointer(s, tile->YData);
		Stream_Seek(s, tile->YLen);
		Stream_GetPointer(s, tile->CbData);
		Stream_Seek(s, tile->CbLen);
		Stream_GetPointer(s, tile->CrData);
		Stream_Seek(s, tile->CrLen);

		tile->x = tile->xIdx * 64;
		tile->y = tile->yIdx * 64;

		if (context->priv->UseThreads)
		{
			assert(params);

			params[i].context = context;
			params[i].tile = message->tiles[i];

			if (!(work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_process_message_tile_work_callback,
					(void*) &params[i], &context->priv->ThreadPoolEnv)))
			{
				WLog_ERR(TAG, "CreateThreadpoolWork failed.");
				rc = FALSE;
				break;
			}

			SubmitThreadpoolWork(work_objects[i]);
			close_cnt = i + 1;
		}
		else
		{
			rfx_decode_rgb(context, tile, tile->data, 64 * 4);
		}

		Stream_SetPosition(s, pos);
	}

	if (context->priv->UseThreads)
	{
		for (i = 0; i < close_cnt; i++)
		{
			WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE);
			CloseThreadpoolWork(work_objects[i]);
		}

		free(work_objects);
		free(params);
	}

	for (i = 0; i < message->numTiles; i++)
	{
		if (!(tile = message->tiles[i]))
			continue;
		tile->YLen = tile->CbLen = tile->CrLen = 0;
		tile->YData = tile->CbData = tile->CrData = NULL;
	}

	return rc;
}
Пример #23
0
Файл: rfx.c Проект: C4rt/FreeRDP
static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s, UINT16* pExpectedBlockType)
{
	int i;
	UINT16 regionType;
	UINT16 numTileSets;

	if (*pExpectedBlockType != WBT_REGION)
	{
		WLog_ERR(TAG, "%s: message unexpeced", __FUNCTION__);
		return FALSE;
	}
	*pExpectedBlockType = WBT_EXTENSION;

	if (Stream_GetRemainingLength(s) < 3)
	{
		WLog_ERR(TAG, "%s: packet too small (regionFlags/numRects)", __FUNCTION__);
		return FALSE;
	}

	Stream_Seek_UINT8(s); /* regionFlags (1 byte) */
	Stream_Read_UINT16(s, message->numRects); /* numRects (2 bytes) */

	if (message->numRects < 1)
	{
		/* Unfortunately, it isn't documented.
		It seems that server asks to clip whole session when numRects = 0.
		Issue: https://github.com/FreeRDP/FreeRDP/issues/1738 */
		WLog_ERR(TAG, "no rects. Clip whole session.");

		if (!(message->rects = (RFX_RECT*) malloc(sizeof(RFX_RECT))))
			return FALSE;

		message->numRects = 1;
		message->rects->x = 0;
		message->rects->y = 0;
		message->rects->width = context->width;
		message->rects->height = context->height;

		return TRUE;
	}

	if (Stream_GetRemainingLength(s) < (size_t) (8 * message->numRects))
	{
		WLog_ERR(TAG, "%s: packet too small for num_rects=%d", __FUNCTION__, message->numRects);
		return FALSE;
	}

	if (!(message->rects = (RFX_RECT*) calloc(message->numRects, sizeof(RFX_RECT))))
		return FALSE;

	/* rects */
	for (i = 0; i < message->numRects; i++)
	{
		/* RFX_RECT */
		Stream_Read_UINT16(s, message->rects[i].x); /* x (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].y); /* y (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].width); /* width (2 bytes) */
		Stream_Read_UINT16(s, message->rects[i].height); /* height (2 bytes) */

		WLog_Print(context->priv->log, WLOG_DEBUG, "rect %d (x,y=%d,%d w,h=%d %d).", i,
				message->rects[i].x, message->rects[i].y,
				message->rects[i].width, message->rects[i].height);
	}

	if (Stream_GetRemainingLength(s) < 4)
	{
		WLog_ERR(TAG, "%s: packet too small (regionType/numTileSets)", __FUNCTION__);
		return FALSE;
	}

	Stream_Read_UINT16(s, regionType); /* regionType (2 bytes): MUST be set to CBT_REGION (0xCAC1) */
	Stream_Read_UINT16(s, numTileSets); /* numTilesets (2 bytes): MUST be set to 0x0001. */

	if (regionType != CBT_REGION)
	{
		WLog_ERR(TAG, "%s: invalid region type 0x%04X", __FUNCTION__, regionType);
		return TRUE;
	}

	if (numTileSets != 0x0001)
	{
		WLog_ERR(TAG, "%s: invalid number of tilesets (%u)", __FUNCTION__, numTileSets);
		return FALSE;
	}

	return TRUE;
}
Пример #24
0
BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
{
	char* str = NULL;
	UINT32 version;
	BYTE connectionType = 0;
	UINT32 clientColorDepth;
	UINT16 colorDepth = 0;
	UINT16 postBeta2ColorDepth = 0;
	UINT16 highColorDepth = 0;
	UINT16 supportedColorDepths = 0;
	UINT32 serverSelectedProtocol = 0;
	UINT32 desktopPhysicalWidth = 0;
	UINT32 desktopPhysicalHeight = 0;
	UINT16 desktopOrientation = 0;
	UINT32 desktopScaleFactor = 0;
	UINT32 deviceScaleFactor = 0;
	UINT16 earlyCapabilityFlags = 0;
	rdpSettings* settings = mcs->settings;

	/* Length of all required fields, until imeFileName */
	if (blockLength < 128)
		return FALSE;

	Stream_Read_UINT32(s, version); /* version (4 bytes) */
	settings->RdpVersion = (version == RDP_VERSION_4 ? 4 : 7);

	Stream_Read_UINT16(s, settings->DesktopWidth); /* DesktopWidth (2 bytes) */
	Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight (2 bytes) */
	Stream_Read_UINT16(s, colorDepth); /* ColorDepth (2 bytes) */
	Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) (2 bytes) */
	Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout (4 bytes) */
	Stream_Read_UINT32(s, settings->ClientBuild); /* ClientBuild (4 bytes) */

	/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
	ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL);
	Stream_Seek(s, 32);
	sprintf_s(settings->ClientHostname, 31, "%s", str);
	settings->ClientHostname[31] = 0;
	free(str);
	str = NULL;

	Stream_Read_UINT32(s, settings->KeyboardType); /* KeyboardType (4 bytes) */
	Stream_Read_UINT32(s, settings->KeyboardSubType); /* KeyboardSubType (4 bytes) */
	Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey (4 bytes) */

	WLog_DBG(TAG, "KeyboardLayout=%x, KeyboardType=%x, KeyboardSubType=%x, KeyboardFunctionKey=%x",
		settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType, settings->KeyboardFunctionKey);

	Stream_Seek(s, 64); /* imeFileName (64 bytes) */

	blockLength -= 128;

	/**
	 * The following fields are all optional. If one field is present, all of the preceding
	 * fields MUST also be present. If one field is not present, all of the subsequent fields
	 * MUST NOT be present.
	 * We must check the bytes left before reading each field.
	 */

	do
	{
		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth (2 bytes) */
		blockLength -= 2;

		if (blockLength < 2)
			break;
		Stream_Seek_UINT16(s); /* clientProductID (2 bytes) */
		blockLength -= 2;

		if (blockLength < 4)
			break;
		Stream_Seek_UINT32(s); /* serialNumber (4 bytes) */
		blockLength -= 4;

		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, highColorDepth); /* highColorDepth (2 bytes) */
		blockLength -= 2;

		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, supportedColorDepths); /* supportedColorDepths (2 bytes) */
		blockLength -= 2;

		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */
		settings->EarlyCapabilityFlags = (UINT32) earlyCapabilityFlags;
		blockLength -= 2;

		if (blockLength < 64)
			break;

		ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL);
		Stream_Seek(s, 64); /* clientDigProductId (64 bytes) */
		sprintf_s(settings->ClientProductId, 32, "%s", str);
		free(str);
		blockLength -= 64;

		if (blockLength < 1)
			break;
		Stream_Read_UINT8(s, connectionType); /* connectionType (1 byte) */
		blockLength -= 1;

		if (blockLength < 1)
			break;
		Stream_Seek_UINT8(s); /* pad1octet (1 byte) */
		blockLength -= 1;

		if (blockLength < 4)
			break;
		Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol (4 bytes) */
		blockLength -= 4;

		if (blockLength < 4)
			break;
		Stream_Read_UINT32(s, desktopPhysicalWidth); /* desktopPhysicalWidth (4 bytes) */
		blockLength -= 4;

		if (blockLength < 4)
			break;
		Stream_Read_UINT32(s, desktopPhysicalHeight); /* desktopPhysicalHeight (4 bytes) */
		blockLength -= 4;

		if (blockLength < 2)
			break;
		Stream_Read_UINT16(s, desktopOrientation); /* desktopOrientation (2 bytes) */
		blockLength -= 2;

		if (blockLength < 4)
			break;
		Stream_Read_UINT32(s, desktopScaleFactor); /* desktopScaleFactor (4 bytes) */
		blockLength -= 4;

		if (blockLength < 4)
			break;
		Stream_Read_UINT32(s, deviceScaleFactor); /* deviceScaleFactor (4 bytes) */
		blockLength -= 4;

		if (settings->SelectedProtocol != serverSelectedProtocol)
			return FALSE;
	} while (0);

	if (highColorDepth > 0)
	{
		if (earlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION)
			clientColorDepth = 32;
		else
			clientColorDepth = highColorDepth;
	}
	else if (postBeta2ColorDepth > 0)
	{
		switch (postBeta2ColorDepth)
		{
			case RNS_UD_COLOR_4BPP:
				clientColorDepth = 4;
				break;
			case RNS_UD_COLOR_8BPP:
				clientColorDepth = 8;
				break;
			case RNS_UD_COLOR_16BPP_555:
				clientColorDepth = 15;
				break;
			case RNS_UD_COLOR_16BPP_565:
				clientColorDepth = 16;
				break;
			case RNS_UD_COLOR_24BPP:
				clientColorDepth = 24;
				break;
			default:
				return FALSE;
		}
	}
	else
	{
		switch (colorDepth)
		{
			case RNS_UD_COLOR_4BPP:
				clientColorDepth = 4;
				break;
			case RNS_UD_COLOR_8BPP:
				clientColorDepth = 8;
				break;
			default:
				return FALSE;
		}
	}

	/*
	 * If we are in server mode, accept client's color depth only if
	 * it is smaller than ours. This is what Windows server does.
	 */
	if ((clientColorDepth < settings->ColorDepth) || !settings->ServerMode)
		settings->ColorDepth = clientColorDepth;

	if (settings->NetworkAutoDetect)
		settings->NetworkAutoDetect = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_NETWORK_AUTODETECT) ? TRUE : FALSE;

	if (settings->SupportHeartbeatPdu)
		settings->SupportHeartbeatPdu = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) ? TRUE : FALSE;

	if (settings->SupportGraphicsPipeline)
		settings->SupportGraphicsPipeline = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) ? TRUE : FALSE;

	if (settings->SupportDynamicTimeZone)
		settings->SupportDynamicTimeZone = (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) ? TRUE : FALSE;

	if (!(earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE))
		connectionType = 0;

	settings->SupportErrorInfoPdu = earlyCapabilityFlags & RNS_UD_CS_SUPPORT_ERRINFO_PDU;

	settings->ConnectionType = connectionType;

	return TRUE;
}
Пример #25
0
BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input)
{
	char* s = NULL;
        mode_t m;
	UINT64 size;
	int status;
	char* fullpath;
	struct STAT st;
	struct timeval tv[2];
	UINT64 LastWriteTime;
	UINT32 FileAttributes;
	UINT32 FileNameLength;

	m = 0;

	switch (FsInformationClass)
	{
		case FileBasicInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232094.aspx */
			Stream_Seek_UINT64(input); /* CreationTime */
			Stream_Seek_UINT64(input); /* LastAccessTime */
			Stream_Read_UINT64(input, LastWriteTime);
			Stream_Seek_UINT64(input); /* ChangeTime */
			Stream_Read_UINT32(input, FileAttributes);

			if (FSTAT(file->fd, &st) != 0)
				return FALSE;

			tv[0].tv_sec = st.st_atime;
			tv[0].tv_usec = 0;
			tv[1].tv_sec = (LastWriteTime > 0 ? FILE_TIME_RDP_TO_SYSTEM(LastWriteTime) : st.st_mtime);
			tv[1].tv_usec = 0;
#ifndef WIN32
/* TODO on win32 */                        
#ifdef ANDROID
			utimes(file->fullpath, tv);
#else
			futimes(file->fd, tv);
#endif

			if (FileAttributes > 0)
			{
				m = st.st_mode;
				if ((FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
					m |= S_IWUSR;
				else
					m &= ~S_IWUSR;
				if (m != st.st_mode)
					fchmod(file->fd, m);
			}
#endif
                        break;

		case FileEndOfFileInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232067.aspx */
		case FileAllocationInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232076.aspx */
			Stream_Read_UINT64(input, size);
			if (ftruncate(file->fd, size) != 0)
				return FALSE;
			break;

		case FileDispositionInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232098.aspx */
			/* http://msdn.microsoft.com/en-us/library/cc241371.aspx */
			if (Length)
				Stream_Read_UINT8(input, file->delete_pending);
			else
				file->delete_pending = 1;
			if (file->delete_pending && file->is_dir)
			{
				/* mstsc causes this to FAIL if the directory is not empty,
				 * and that's what the server is expecting.  If we wait for
				 * the close to flag a failure, cut and paste of a folder
				 * will lose the folder's contents.
				 */
				int status;
				status = rmdir(file->fullpath);
				if (status == 0)
				{
					/* Put it back so the normal pending delete will work. */
					mkdir(file->fullpath, 0755);
				}
				else
				{
					return FALSE;
				}
			}
			break;

		case FileRenameInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232085.aspx */
			Stream_Seek_UINT8(input); /* ReplaceIfExists */
			Stream_Seek_UINT8(input); /* RootDirectory */
			Stream_Read_UINT32(input, FileNameLength);

			status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(input),
					FileNameLength / 2, &s, 0, NULL, NULL);

			if (status < 1)
				s = (char*) calloc(1, 1);

			fullpath = drive_file_combine_fullpath(file->basepath, s);
			free(s);

			/* TODO rename does not work on win32 */
                        if (rename(file->fullpath, fullpath) == 0)
			{
				DEBUG_SVC("renamed %s to %s", file->fullpath, fullpath);
				drive_file_set_fullpath(file, fullpath);
			}
			else
			{
				DEBUG_WARN("rename %s to %s failed, errno = %d", file->fullpath, fullpath, errno);
				free(fullpath);
				return FALSE;
			}

			break;

		default:
			DEBUG_WARN("invalid FsInformationClass %d", FsInformationClass);
			return FALSE;
	}

	return TRUE;
}
Пример #26
0
static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
{
	int i, num_known_format = 0;
	UINT32 flags, vol, pitch;
	UINT16 udpPort, version;
	BYTE lastblock;

	if (Stream_GetRemainingLength(s) < 20)
		return FALSE;

	Stream_Read_UINT32(s, flags); /* dwFlags */
	Stream_Read_UINT32(s, vol); /* dwVolume */
	Stream_Read_UINT32(s, pitch); /* dwPitch */
	Stream_Read_UINT16(s, udpPort); /* wDGramPort */
	Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
	Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
	Stream_Read_UINT16(s, version); /* wVersion */
	Stream_Seek_UINT8(s); /* bPad */

	/* this check is only a guess as cbSize can influence the size of a format record */
	if (Stream_GetRemainingLength(s) < context->num_client_formats * 18)
		return FALSE;

	if (!context->num_client_formats)
	{
		fprintf(stderr, "%s: client doesn't support any format!\n", __FUNCTION__);
		return FALSE;
	}

	context->client_formats = (AUDIO_FORMAT *)calloc(context->num_client_formats, sizeof(AUDIO_FORMAT));
	if (!context->client_formats)
		return FALSE;

	for (i = 0; i < context->num_client_formats; i++)
	{
		if (Stream_GetRemainingLength(s) < 18)
			goto out_free;

		Stream_Read_UINT16(s, context->client_formats[i].wFormatTag);
		Stream_Read_UINT16(s, context->client_formats[i].nChannels);
		Stream_Read_UINT32(s, context->client_formats[i].nSamplesPerSec);
		Stream_Read_UINT32(s, context->client_formats[i].nAvgBytesPerSec);
		Stream_Read_UINT16(s, context->client_formats[i].nBlockAlign);
		Stream_Read_UINT16(s, context->client_formats[i].wBitsPerSample);
		Stream_Read_UINT16(s, context->client_formats[i].cbSize);

		if (context->client_formats[i].cbSize > 0)
		{
			if (!Stream_SafeSeek(s, context->client_formats[i].cbSize))
				goto out_free;
		}

		if (context->client_formats[i].wFormatTag != 0)
		{
			//lets call this a known format
			//TODO: actually look through our own list of known formats
			num_known_format++;
		}
	}

	if (!context->num_client_formats)
	{
		fprintf(stderr, "%s: client doesn't support any known format!\n", __FUNCTION__);
		goto out_free;
	}

	return TRUE;

out_free:
	free(context->client_formats);
	return FALSE;
}
Пример #27
0
static void* rdpsnd_server_thread(void* arg)
{
	wStream* s;
	DWORD status;
	DWORD nCount;
	void* buffer;
	BYTE msgType;
	UINT16 BodySize;
	HANDLE events[8];
	HANDLE ChannelEvent;
	DWORD BytesReturned;
	RdpsndServerContext* context;
	BOOL doRun;

	context = (RdpsndServerContext *)arg;

	buffer = NULL;
	BytesReturned = 0;
	ChannelEvent = NULL;

	s = Stream_New(NULL, 4096);
	if (!s)
		return NULL;

	if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned))
	{
		if (BytesReturned == sizeof(HANDLE))
			CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));

		WTSFreeMemory(buffer);
	}

	nCount = 0;
	if (ChannelEvent)
		events[nCount++] = ChannelEvent;
	events[nCount++] = context->priv->StopEvent;

	if (!rdpsnd_server_send_formats(context, s))
		goto out;

	doRun = TRUE;
	while (doRun)
	{
		status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);

		if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
			break;

		Stream_SetPosition(s, 0);

		if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s),
									Stream_Capacity(s), &BytesReturned))
		{
			if (!BytesReturned)
				break;

			Stream_EnsureRemainingCapacity(s, BytesReturned);

			if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s),
										Stream_Capacity(s), &BytesReturned))
				break;
		}

		if (Stream_GetRemainingLength(s) < 4)
			break;

		Stream_Read_UINT8(s, msgType);
		Stream_Seek_UINT8(s); /* bPad */
		Stream_Read_UINT16(s, BodySize);

		if (Stream_GetRemainingLength(s) < BodySize)
			break;

		switch (msgType)
		{
			case SNDC_WAVECONFIRM:
				doRun = rdpsnd_server_recv_waveconfirm(context, s);
				break;

			case SNDC_QUALITYMODE:
				doRun = rdpsnd_server_recv_quality_mode(context, s);
				break;

			case SNDC_FORMATS:
				doRun = rdpsnd_server_recv_formats(context, s);
				if (doRun)
				{
					IFCALL(context->Activated, context);
				}
				break;

			default:
				fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, msgType);
				break;
		}
	}

out:
	Stream_Free(s, TRUE);
	return NULL;
}
Пример #28
0
static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s)
{
	int i;
	int pos;
	BYTE quant;
	UINT32* quants;
	UINT16 subtype;
	UINT32 blockLen;
	UINT32 blockType;
	UINT32 tilesDataSize;
	PTP_WORK* work_objects = NULL;
	RFX_TILE_WORK_PARAM* params = NULL;

	if (Stream_GetRemainingLength(s) < 14)
	{
		DEBUG_WARN("RfxMessageTileSet packet too small");
		return FALSE;
	}

	Stream_Read_UINT16(s, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */

	if (subtype != CBT_TILESET)
	{
		DEBUG_WARN("invalid subtype, expected CBT_TILESET.");
		return FALSE;
	}

	Stream_Seek_UINT16(s); /* idx (2 bytes), must be set to 0x0000 */
	Stream_Seek_UINT16(s); /* properties (2 bytes) */

	Stream_Read_UINT8(s, context->num_quants); /* numQuant (1 byte) */
	Stream_Seek_UINT8(s); /* tileSize (1 byte), must be set to 0x40 */

	if (context->num_quants < 1)
	{
		DEBUG_WARN("no quantization value.");
		return TRUE;
	}

	Stream_Read_UINT16(s, message->num_tiles); /* numTiles (2 bytes) */

	if (message->num_tiles < 1)
	{
		DEBUG_WARN("no tiles.");
		return TRUE;
	}

	Stream_Read_UINT32(s, tilesDataSize); /* tilesDataSize (4 bytes) */

	if (context->quants != NULL)
		context->quants = (UINT32*) realloc((void*) context->quants, context->num_quants * 10 * sizeof(UINT32));
	else
		context->quants = (UINT32*) malloc(context->num_quants * 10 * sizeof(UINT32));
	quants = context->quants;

	/* quantVals */
	if (Stream_GetRemainingLength(s) < context->num_quants * 5)
	{
		DEBUG_WARN("RfxMessageTileSet packet too small for num_quants=%d", context->num_quants);
		return FALSE;
	}

	for (i = 0; i < context->num_quants; i++)
	{
		/* RFX_CODEC_QUANT */
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);
		Stream_Read_UINT8(s, quant);
		*quants++ = (quant & 0x0F);
		*quants++ = (quant >> 4);

		DEBUG_RFX("quant %d (%d %d %d %d %d %d %d %d %d %d).",
			i, context->quants[i * 10], context->quants[i * 10 + 1],
			context->quants[i * 10 + 2], context->quants[i * 10 + 3],
			context->quants[i * 10 + 4], context->quants[i * 10 + 5],
			context->quants[i * 10 + 6], context->quants[i * 10 + 7],
			context->quants[i * 10 + 8], context->quants[i * 10 + 9]);
	}

	message->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->num_tiles);
	ZeroMemory(message->tiles, sizeof(RFX_TILE*) * message->num_tiles);

	if (context->priv->UseThreads)
	{
		work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->num_tiles);
		params = (RFX_TILE_WORK_PARAM*) malloc(sizeof(RFX_TILE_WORK_PARAM) * message->num_tiles);
	}

	/* tiles */
	for (i = 0; i < message->num_tiles; i++)
	{
		/* RFX_TILE */
		if (Stream_GetRemainingLength(s) < 6)
		{
			DEBUG_WARN("RfxMessageTileSet packet too small to read tile %d/%d", i, message->num_tiles);
			return FALSE;
		}

		Stream_Read_UINT16(s, blockType); /* blockType (2 bytes), must be set to CBT_TILE (0xCAC3) */
		Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */

		if (Stream_GetRemainingLength(s) < blockLen - 6)
		{
			DEBUG_WARN("RfxMessageTileSet not enough bytes to read tile %d/%d with blocklen=%d", i, message->num_tiles, blockLen);
			return FALSE;
		}

		pos = Stream_GetPosition(s) - 6 + blockLen;

		if (blockType != CBT_TILE)
		{
			DEBUG_WARN("unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType);
			break;
		}

		message->tiles[i] = rfx_tile_pool_take(context);

		if (context->priv->UseThreads)
		{
			params[i].context = context;
			params[i].tile = message->tiles[i];
			CopyMemory(&(params[i].s), s, sizeof(wStream));

			work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_process_message_tile_work_callback,
					(void*) &params[i], &context->priv->ThreadPoolEnv);

			SubmitThreadpoolWork(work_objects[i]);
		}
		else
		{
			rfx_process_message_tile(context, message->tiles[i], s);
		}

		Stream_SetPosition(s, pos);
	}

	if (context->priv->UseThreads)
	{
		for (i = 0; i < message->num_tiles; i++)
		{
			WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE);
			CloseThreadpoolWork(work_objects[i]);
		}

		free(work_objects);
		free(params);
	}
	return TRUE;
}